8141132: JEP 254: Compact Strings

Adopt a more space-efficient internal representation for strings.

Co-authored-by: Brent Christian <brent.christian@oracle.com>
Co-authored-by: Vivek Deshpande <vivek.r.deshpande@intel.com>
Co-authored-by: Charlie Hunt <charlie.hunt@oracle.com>
Co-authored-by: Vladimir Kozlov <vladimir.kozlov@oracle.com>
Co-authored-by: Roger Riggs <roger.riggs@oracle.com>
Co-authored-by: Xueming Shen <xueming.shen@oracle.com>
Co-authored-by: Aleksey Shipilev <aleksey.shipilev@oracle.com>
Co-authored-by: Sandhya Viswanathan <sandhya.viswanathan@intel.com>
Reviewed-by: alanb, bdelsart, coleenp, iklam, jiangli, jrose, kevinw, naoto, pliden, roland, smarks, twisti
This commit is contained in:
Tobias Hartmann 2015-11-03 09:42:11 +01:00
parent b7dca6971d
commit 4ed5b73f3d
76 changed files with 8755 additions and 1288 deletions

View File

@ -50,12 +50,12 @@ public class $NAME_CLZ$ extends Charset
public CharsetDecoder newDecoder() {
initb2c();
return new DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$);
return new DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$, $ASCIICOMPATIBLE$);
}
public CharsetEncoder newEncoder() {
initc2b();
return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex);
return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex, $ASCIICOMPATIBLE$);
}
$B2C$

View File

@ -48,11 +48,11 @@ public class $NAME_CLZ$ extends Charset implements HistoricallyNamedCharset
}
public CharsetDecoder newDecoder() {
return new SingleByte.Decoder(this, b2c);
return new SingleByte.Decoder(this, b2c, $ASCIICOMPATIBLE$);
}
public CharsetEncoder newEncoder() {
return new SingleByte.Encoder(this, c2b, c2bIndex);
return new SingleByte.Encoder(this, c2b, c2bIndex, $ASCIICOMPATIBLE$);
}
private final static String b2cTable = $B2CTABLE$

View File

@ -211,6 +211,7 @@ SUNWprivate_1.1 {
Java_java_lang_SecurityManager_getClassContext;
Java_java_lang_Shutdown_halt0;
Java_java_lang_String_intern;
Java_java_lang_StringUTF16_isBigEndian;
Java_java_lang_System_identityHashCode;
Java_java_lang_System_initProperties;
Java_java_lang_System_mapLibraryName;

View File

@ -57,6 +57,7 @@ text: .text%Java_java_io_UnixFileSystem_list;
text: .text%JNU_ClassString;
text: .text%JNU_CopyObjectArray;
text: .text%Java_java_lang_String_intern;
text: .text%Java_java_lang_StringUTF16_isBigEndian;
text: .text%Java_java_lang_ClassLoader_findLoadedClass0;
text: .text%Java_java_lang_ClassLoader_findBootstrapClass;
text: .text%Java_java_lang_Throwable_fillInStackTrace;

View File

@ -29,6 +29,7 @@ text: .text%Java_sun_reflect_Reflection_getCallerClass__;
text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
text: .text%Java_java_lang_Class_forName0;
text: .text%Java_java_lang_String_intern;
text: .text%Java_java_lang_StringUTF16_isBigEndian;
text: .text%Java_java_lang_Float_floatToRawIntBits;
text: .text%Java_java_lang_Double_doubleToRawLongBits;
text: .text%Java_java_lang_ClassLoader_findLoadedClass0;

View File

@ -31,6 +31,7 @@ text: .text%Java_sun_reflect_Reflection_getCallerClass__;
text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
text: .text%Java_java_lang_Class_forName0;
text: .text%Java_java_lang_String_intern;
text: .text%Java_java_lang_StringUTF16_isBigEndian;
text: .text%Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0;
text: .text%Java_java_lang_Throwable_fillInStackTrace;
text: .text%Java_java_lang_System_setOut0;

View File

@ -197,6 +197,7 @@ public class DBCS {
.replace("$B1MAX$" , "0x" + Integer.toString(b1Max, 16))
.replace("$B2MIN$" , "0x" + Integer.toString(b2Min, 16))
.replace("$B2MAX$" , "0x" + Integer.toString(b2Max, 16))
.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false")
.replace("$B2C$", b2c)
.replace("$C2BLENGTH$", "0x" + Integer.toString(c2bOff, 16))
.replace("$NONROUNDTRIP_B2C$", b2cNR)

View File

@ -175,6 +175,9 @@ public class SBCS {
else
line = " return (cs instanceof " + clzName + ");";
}
if (line.indexOf("$ASCIICOMPATIBLE$") != -1) {
line = line.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false");
}
if (line.indexOf("$B2CTABLE$") != -1) {
line = line.replace("$B2CTABLE$", b2c);
}

View File

@ -31,6 +31,12 @@ import java.util.Spliterator;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.UTF16;
import static java.lang.String.LATIN1;
import static java.lang.String.checkIndex;
import static java.lang.String.checkOffset;
/**
* A mutable sequence of characters.
* <p>
@ -51,7 +57,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
byte[] value;
/**
* The id of the encoding used to encode the bytes in {@code value}.
*/
byte coder;
/**
* The count is the number of characters used.
@ -68,7 +79,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);
coder = UTF16;
}
}
/**
@ -90,7 +107,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return the current capacity
*/
public int capacity() {
return value.length;
return value.length >> coder;
}
/**
@ -110,8 +127,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @param minimumCapacity the minimum desired capacity.
*/
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
if (minimumCapacity > 0) {
ensureCapacityInternal(minimumCapacity);
}
}
/**
@ -120,24 +138,48 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
int capacity = value.length >> coder;
if (minimumCapacity - capacity > 0) {
expandCapacity(minimumCapacity);
}
}
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
private void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length >> coder) * 2 + 2;
if (newCapacity - minimumCapacity < 0) {
newCapacity = minimumCapacity;
}
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
if (minimumCapacity < 0) {// overflow
throw new OutOfMemoryError();
}
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
if (coder != LATIN1 && newCapacity > StringUTF16.MAX_LENGTH) {
if (minimumCapacity >= StringUTF16.MAX_LENGTH) {
throw new OutOfMemoryError();
}
newCapacity = StringUTF16.MAX_LENGTH;
}
this.value = Arrays.copyOf(value, newCapacity << coder);
}
/**
* If the coder is "isLatin1", this inflates the internal 8-bit storage
* to 16-bit <hi=0, low> pair storage.
*/
private void inflate() {
if (!isLatin1()) {
return;
}
byte[] buf = StringUTF16.newBytesFor(value.length);
StringLatin1.inflateSB(value, buf, 0, count);
this.value = buf;
this.coder = UTF16;
}
/**
@ -148,8 +190,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* returned by a subsequent call to the {@link #capacity()} method.
*/
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
int length = count << coder;
if (length < value.length) {
value = Arrays.copyOf(value, length);
}
}
@ -179,14 +222,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code newLength} argument is negative.
*/
public void setLength(int newLength) {
if (newLength < 0)
if (newLength < 0) {
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength) {
Arrays.fill(value, count, newLength, '\0');
}
ensureCapacityInternal(newLength);
if (count < newLength) {
if (isLatin1()) {
StringLatin1.fillNull(value, count, newLength);
} else {
StringUTF16.fillNull(value, count, newLength);
}
}
count = newLength;
}
@ -209,9 +255,11 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
@Override
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
checkIndex(index, count);
if (isLatin1()) {
return (char)(value[index] & 0xff);
}
return StringUTF16.charAt(value, index);
}
/**
@ -236,10 +284,11 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* sequence.
*/
public int codePointAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
checkIndex(index, count);
if (isLatin1()) {
return value[index] & 0xff;
}
return Character.codePointAtImpl(value, index, count);
return StringUTF16.codePointAtSB(value, index, count);
}
/**
@ -265,10 +314,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {
if (i < 0 || i >= count) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
if (isLatin1()) {
return value[i] & 0xff;
}
return StringUTF16.codePointBeforeSB(value, index);
}
/**
@ -295,7 +347,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
if (isLatin1()) {
return endIndex - beginIndex;
}
return StringUTF16.codePointCountSB(value, beginIndex, endIndex);
}
/**
@ -321,8 +376,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
if (index < 0 || index > count) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, count,
index, codePointOffset);
return Character.offsetByCodePoints(this,
index, codePointOffset);
}
/**
@ -355,13 +410,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
checkRangeSIOOBE(srcBegin, srcEnd, count); // compatible to old version
int n = srcEnd - srcBegin;
checkRange(dstBegin, dstBegin + n, dst.length);
if (isLatin1()) {
StringLatin1.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
} else {
StringUTF16.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
}
}
/**
@ -379,9 +435,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* negative or greater than or equal to {@code length()}.
*/
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
checkIndex(index, count);
if (isLatin1() && StringLatin1.canEncode(ch)) {
value[index] = (byte)ch;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, index, ch);
}
}
/**
@ -418,35 +480,34 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return a reference to this object.
*/
public AbstractStringBuilder append(String str) {
if (str == null)
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
putStringAt(count, str);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
return this.append((AbstractStringBuilder)sb);
}
/**
* @since 1.8
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
if (asb == null) {
return appendNull();
}
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
if (getCoder() != asb.getCoder()) {
inflate();
}
asb.getBytes(value, count, coder);
count += len;
return this;
}
@ -454,25 +515,35 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
// Documentation in subclasses because of synchro difference
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
if (s == null) {
return appendNull();
if (s instanceof String)
}
if (s instanceof String) {
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
}
if (s instanceof AbstractStringBuilder) {
return this.append((AbstractStringBuilder)s);
}
return this.append(s, 0, s.length());
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
ensureCapacityInternal(count + 4);
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
} else {
checkOffset(count + 4, val.length >> 1);
StringUTF16.putChar(val, count++, 'n');
StringUTF16.putChar(val, count++, 'u');
StringUTF16.putChar(val, count++, 'l');
StringUTF16.putChar(val, count++, 'l');
}
this.count = count;
return this;
}
@ -507,21 +578,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
if (s == null) {
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
}
checkRange(start, end, s.length());
int len = end - start;
ensureCapacityInternal(count + len);
if (s instanceof String) {
((String)s).getChars(start, end, value, count);
} else {
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
}
count += len;
appendChars(s, start, end);
return this;
}
@ -544,8 +607,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
appendChars(str, 0, len);
return this;
}
@ -572,10 +634,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* or {@code offset+len > str.length}
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
int end = offset + len;
checkRange(offset, end, str.length);
ensureCapacityInternal(count + len);
appendChars(str, offset, end);
return this;
}
@ -592,20 +654,39 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return a reference to this object.
*/
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
ensureCapacityInternal(count + (b ? 4 : 5));
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
if (b) {
val[count++] = 't';
val[count++] = 'r';
val[count++] = 'u';
val[count++] = 'e';
} else {
val[count++] = 'f';
val[count++] = 'a';
val[count++] = 'l';
val[count++] = 's';
val[count++] = 'e';
}
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
if (b) {
checkOffset(count + 4, val.length >> 1);
StringUTF16.putChar(val, count++, 't');
StringUTF16.putChar(val, count++, 'r');
StringUTF16.putChar(val, count++, 'u');
StringUTF16.putChar(val, count++, 'e');
} else {
checkOffset(count + 5, val.length >> 1);
StringUTF16.putChar(val, count++, 'f');
StringUTF16.putChar(val, count++, 'a');
StringUTF16.putChar(val, count++, 'l');
StringUTF16.putChar(val, count++, 's');
StringUTF16.putChar(val, count++, 'e');
}
}
this.count = count;
return this;
}
@ -627,7 +708,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
if (isLatin1() && StringLatin1.canEncode(c)) {
value[count++] = (byte)c;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, count++, c);
}
return this;
}
@ -652,7 +740,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
if (isLatin1()) {
Integer.getChars(i, spaceNeeded, value);
} else {
byte[] val = this.value;
checkOffset(spaceNeeded, val.length >> 1);
Integer.getCharsUTF16(i, spaceNeeded, val);
}
count = spaceNeeded;
return this;
}
@ -678,7 +772,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
if (isLatin1()) {
Long.getChars(l, spaceNeeded, value);
} else {
byte[] val = this.value;
checkOffset(spaceNeeded, val.length >> 1);
Long.getCharsUTF16(l, spaceNeeded, val);
}
count = spaceNeeded;
return this;
}
@ -732,15 +832,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* greater than {@code end}.
*/
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
if (end > count) {
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
}
checkRangeSIOOBE(start, end, count);
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
shift(end, -len);
count -= len;
}
return this;
@ -766,20 +864,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code codePoint} isn't a valid Unicode code point
*/
public AbstractStringBuilder appendCodePoint(int codePoint) {
final int count = this.count;
if (Character.isBmpCodePoint(codePoint)) {
ensureCapacityInternal(count + 1);
value[count] = (char) codePoint;
this.count = count + 1;
} else if (Character.isValidCodePoint(codePoint)) {
ensureCapacityInternal(count + 2);
Character.toSurrogates(codePoint, value, count);
this.count = count + 2;
} else {
throw new IllegalArgumentException();
return append((char)codePoint);
}
return this;
return append(Character.toChars(codePoint));
}
/**
@ -800,9 +888,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code length()}.
*/
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
checkIndex(index, count);
shift(index + 1, -1);
count--;
return this;
}
@ -827,22 +914,16 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* greater than {@code end}.
*/
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end");
if (end > count)
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
shift(end, newCount - count);
count = newCount;
putStringAt(start, str);
return this;
}
@ -907,13 +988,16 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* greater than {@code end}.
*/
public String substring(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
throw new StringIndexOutOfBoundsException(end);
if (start > end)
throw new StringIndexOutOfBoundsException(end - start);
return new String(value, start, end - start);
checkRangeSIOOBE(start, end, count);
if (isLatin1()) {
return StringLatin1.newString(value, start, end - start);
}
return StringUTF16.newStringSB(value, start, end - start);
}
private void shift(int offset, int n) {
System.arraycopy(value, offset << coder,
value, (offset + n) << coder, (count - offset) << coder);
}
/**
@ -940,16 +1024,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
if ((index < 0) || (index > length()))
throw new StringIndexOutOfBoundsException(index);
if ((offset < 0) || (len < 0) || (offset > str.length - len))
throw new StringIndexOutOfBoundsException(
"offset " + offset + ", len " + len + ", str.length "
+ str.length);
checkOffset(index, count);
checkRangeSIOOBE(offset, offset + len, str.length);
ensureCapacityInternal(count + len);
System.arraycopy(value, index, value, index + len, count - index);
System.arraycopy(str, offset, value, index, len);
shift(index, len);
count += len;
putCharsAt(index, str, offset, offset + len);
return this;
}
@ -1008,15 +1088,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
public AbstractStringBuilder insert(int offset, String str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
if (str == null)
checkOffset(offset, count);
if (str == null) {
str = "null";
}
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
str.getChars(value, offset);
shift(offset, len);
count += len;
putStringAt(offset, str);
return this;
}
@ -1045,13 +1125,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @throws StringIndexOutOfBoundsException if the offset is invalid.
*/
public AbstractStringBuilder insert(int offset, char[] str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
checkOffset(offset, count);
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
System.arraycopy(str, 0, value, offset, len);
shift(offset, len);
count += len;
putCharsAt(offset, str, 0, len);
return this;
}
@ -1077,10 +1156,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @throws IndexOutOfBoundsException if the offset is invalid.
*/
public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
if (s == null)
if (s == null) {
s = "null";
if (s instanceof String)
}
if (s instanceof String) {
return this.insert(dstOffset, (String)s);
}
return this.insert(dstOffset, s, 0, s.length());
}
@ -1128,23 +1209,19 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code start} is greater than {@code end} or
* {@code end} is greater than {@code s.length()}
*/
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
int start, int end) {
if (s == null)
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
int start, int end)
{
if (s == null) {
s = "null";
if ((dstOffset < 0) || (dstOffset > this.length()))
throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
}
checkOffset(dstOffset, count);
checkRange(start, end, s.length());
int len = end - start;
ensureCapacityInternal(count + len);
System.arraycopy(value, dstOffset, value, dstOffset + len,
count - dstOffset);
for (int i=start; i<end; i++)
value[dstOffset++] = s.charAt(i);
shift(dstOffset, len);
count += len;
putCharsAt(dstOffset, s, start, end);
return this;
}
@ -1191,10 +1268,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @throws IndexOutOfBoundsException if the offset is invalid.
*/
public AbstractStringBuilder insert(int offset, char c) {
checkOffset(offset, count);
ensureCapacityInternal(count + 1);
System.arraycopy(value, offset, value, offset + 1, count - offset);
value[offset] = c;
shift(offset, 1);
count += 1;
if (isLatin1() && StringLatin1.canEncode(c)) {
value[offset] = (byte)c;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, offset, c);
}
return this;
}
@ -1326,7 +1411,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* or {@code -1} if there is no such occurrence.
*/
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count, str, fromIndex);
return String.indexOf(value, coder, count, str, fromIndex);
}
/**
@ -1366,7 +1451,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* or {@code -1} if there is no such occurrence.
*/
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count, str, fromIndex);
return String.lastIndexOf(value, coder, count, str, fromIndex);
}
/**
@ -1392,34 +1477,47 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return a reference to this object.
*/
public AbstractStringBuilder reverse() {
boolean hasSurrogates = false;
byte[] val = this.value;
int count = this.count;
int coder = this.coder;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
char cj = value[j];
char ck = value[k];
value[j] = ck;
value[k] = cj;
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
if (COMPACT_STRINGS && coder == LATIN1) {
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
byte cj = val[j];
val[j] = val[k];
val[k] = cj;
}
} else {
checkOffset(count, val.length >> 1);
boolean hasSurrogates = false;
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
char cj = StringUTF16.getChar(val, j);
char ck = StringUTF16.getChar(val, k);
StringUTF16.putChar(val, j, ck);
StringUTF16.putChar(val, k, cj);
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
}
}
if (hasSurrogates) {
reverseAllValidSurrogatePairs(val, count);
}
}
if (hasSurrogates) {
reverseAllValidSurrogatePairs();
}
return this;
}
/** Outlined helper method for reverse() */
private void reverseAllValidSurrogatePairs() {
private void reverseAllValidSurrogatePairs(byte[] val, int count) {
for (int i = 0; i < count - 1; i++) {
char c2 = value[i];
char c2 = StringUTF16.getChar(val, i);
if (Character.isLowSurrogate(c2)) {
char c1 = value[i + 1];
char c1 = StringUTF16.getChar(val, i + 1);
if (Character.isHighSurrogate(c1)) {
value[i++] = c1;
value[i] = c2;
StringUTF16.putChar(val, i++, c1);
StringUTF16.putChar(val, i, c2);
}
}
}
@ -1444,10 +1542,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
@Override
public IntStream chars() {
byte[] val = this.value; int count = this.count; byte coder = this.coder;
checkOffset(count, val.length >> coder);
// Reuse String-based spliterator. This requires a supplier to
// capture the value and count when the terminal operation is executed
return StreamSupport.intStream(
() -> new String.IntCharArraySpliterator(value, 0, count, 0),
() -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CharsSpliterator(val, 0, count, 0),
Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
false);
}
@ -1458,10 +1559,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
*/
@Override
public IntStream codePoints() {
byte[] val = this.value; int count = this.count; byte coder = this.coder;
checkOffset(count, val.length >> coder);
// Reuse String-based spliterator. This requires a supplier to
// capture the value and count when the terminal operation is executed
return StreamSupport.intStream(
() -> new String.CodePointsSpliterator(value, 0, count, 0),
() -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CodePointsSpliterator(val, 0, count, 0),
Spliterator.ORDERED,
false);
}
@ -1469,8 +1573,147 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
final byte[] getValue() {
return value;
}
/*
* Invoker guarantees it is in UTF16 (inflate itself for asb), if two
* coders are different and the dstBegin has enough space
*
* @param dstBegin the char index, not offset of byte[]
* @param coder the coder of dst[]
*/
protected void getBytes(byte dst[], int dstBegin, byte coder) {
if (this.coder == coder) {
System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
} else { // this.coder == LATIN && coder == UTF16
StringLatin1.inflateSB(value, dst, dstBegin, count);
}
}
/* for readObject() */
protected void initBytes(char[] value, int off, int len) {
if (String.COMPACT_STRINGS) {
this.value = StringUTF16.compress(value, off, len);
if (this.value != null) {
this.coder = LATIN1;
return;
}
}
this.coder = UTF16;
this.value = StringUTF16.toBytes(value, off, len);
}
final byte getCoder() {
return COMPACT_STRINGS ? coder : UTF16;
}
final boolean isLatin1() {
return COMPACT_STRINGS && coder == LATIN1;
}
private final void putCharsAt(int index, char[] s, int off, int end) {
if (isLatin1()) {
byte[] val = this.value;
for (int i = off, j = index; i < end; i++) {
char c = s[i];
if (StringLatin1.canEncode(c)) {
val[j++] = (byte)c;
} else {
inflate();
StringUTF16.putCharsSB(this.value, j, s, i, end);
return;
}
}
} else {
StringUTF16.putCharsSB(this.value, index, s, off, end);
}
}
private final void putCharsAt(int index, CharSequence s, int off, int end) {
if (isLatin1()) {
byte[] val = this.value;
for (int i = off, j = index; i < end; i++) {
char c = s.charAt(i);
if (StringLatin1.canEncode(c)) {
val[j++] = (byte)c;
} else {
inflate();
StringUTF16.putCharsSB(this.value, j, s, i, end);
return;
}
}
} else {
StringUTF16.putCharsSB(this.value, index, s, off, end);
}
}
private final void putStringAt(int index, String str) {
if (getCoder() != str.coder()) {
inflate();
}
byte[] val = this.value;
byte coder = this.coder;
checkOffset(index + str.length(), val.length >> coder);
str.getBytes(val, index, coder);
}
private final void appendChars(char[] s, int off, int end) {
if (isLatin1()) {
byte[] val = this.value;
for (int i = off, j = count; i < end; i++) {
char c = s[i];
if (StringLatin1.canEncode(c)) {
val[j++] = (byte)c;
} else {
count = j;
inflate();
StringUTF16.putCharsSB(this.value, j, s, i, end);
count += end - i;
return;
}
}
} else {
StringUTF16.putCharsSB(this.value, count, s, off, end);
}
count += end - off;
}
private final void appendChars(CharSequence s, int off, int end) {
if (isLatin1()) {
byte[] val = this.value;
for (int i = off, j = count; i < end; i++) {
char c = s.charAt(i);
if (StringLatin1.canEncode(c)) {
val[j++] = (byte)c;
} else {
count = j;
inflate();
StringUTF16.putCharsSB(this.value, j, s, i, end);
count += end - i;
return;
}
}
} else {
StringUTF16.putCharsSB(this.value, count, s, off, end);
}
count += end - off;
}
/* IndexOutOfBoundsException, if out of bounds */
private static void checkRange(int start, int end, int len) {
if (start < 0 || start > end || end > len) {
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", length " + len);
}
}
/* StringIndexOutOfBoundsException, if out of bounds */
private static void checkRangeSIOOBE(int start, int end, int len) {
if (start < 0 || start > end || end > len) {
throw new StringIndexOutOfBoundsException(
"start " + start + ", end " + end + ", length " + len);
}
}
}

View File

@ -29,6 +29,10 @@ import java.lang.annotation.Native;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
/**
* The {@code Integer} class wraps a value of the primitive type
* {@code int} in an object. An object of type {@code Integer}
@ -138,25 +142,47 @@ public final class Integer extends Number implements Comparable<Integer> {
return toString(i);
}
char buf[] = new char[33];
if (COMPACT_STRINGS) {
byte[] buf = new byte[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = (byte)digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = (byte)digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return StringLatin1.newString(buf, charPos, (33 - charPos));
}
return toStringUTF16(i, radix);
}
private static String toStringUTF16(int i, int radix) {
byte[] buf = new byte[33 * 2];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
i = i / radix;
}
buf[charPos] = digits[-i];
StringUTF16.putChar(buf, charPos, digits[-i]);
if (negative) {
buf[--charPos] = '-';
StringUTF16.putChar(buf, --charPos, '-');
}
return new String(buf, charPos, (33 - charPos));
return StringUTF16.newString(buf, charPos, (33 - charPos));
}
/**
@ -312,12 +338,16 @@ public final class Integer extends Number implements Comparable<Integer> {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
char[] buf = new char[chars];
formatUnsignedInt(val, shift, buf, 0, chars);
// Use special constructor which takes over "buf".
return new String(buf, true);
if (COMPACT_STRINGS) {
byte[] buf = new byte[chars];
formatUnsignedInt(val, shift, buf, 0, chars);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[chars * 2];
formatUnsignedIntUTF16(val, shift, buf, 0, chars);
return new String(buf, UTF16);
}
}
/**
@ -331,7 +361,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* @param offset the offset in the destination buffer to start at
* @param len the number of characters to write
*/
static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
// assert offset >= 0 && offset < buf.length : "illegal offset";
// assert len > 0 && (offset + len) <= buf.length : "illegal length";
@ -344,6 +374,28 @@ public final class Integer extends Number implements Comparable<Integer> {
} while (charPos > offset);
}
/** byte[]/LATIN1 version */
static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = (byte)Integer.digits[val & mask];
val >>>= shift;
} while (charPos > offset);
}
/** byte[]/UTF16 version */
static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
val >>>= shift;
} while (charPos > offset);
}
static final char [] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
@ -401,9 +453,15 @@ public final class Integer extends Number implements Comparable<Integer> {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
getChars(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
getCharsUTF16(i, size, buf);
return new String(buf, UTF16);
}
}
/**
@ -433,7 +491,7 @@ public final class Integer extends Number implements Comparable<Integer> {
*
* Will fail if i == Integer.MIN_VALUE
*/
static void getChars(int i, int index, char[] buf) {
static void getChars(int i, int index, byte[] buf) {
int q, r;
int charPos = index;
char sign = 0;
@ -449,8 +507,8 @@ public final class Integer extends Number implements Comparable<Integer> {
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
buf [--charPos] = (byte)DigitOnes[r];
buf [--charPos] = (byte)DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
@ -458,12 +516,46 @@ public final class Integer extends Number implements Comparable<Integer> {
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
buf [--charPos] = (byte)digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
buf [--charPos] = (byte)sign;
}
}
static void getCharsUTF16(int i, int index, byte[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
StringUTF16.putChar(buf, --charPos, DigitOnes[r]);
StringUTF16.putChar(buf, --charPos, DigitTens[r]);
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
i = q;
if (i == 0) break;
}
if (sign != 0) {
StringUTF16.putChar(buf, --charPos, sign);
}
}

View File

@ -30,6 +30,9 @@ import java.math.*;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
/**
* The {@code Long} class wraps a value of the primitive type {@code
@ -124,25 +127,46 @@ public final class Long extends Number implements Comparable<Long> {
radix = 10;
if (radix == 10)
return toString(i);
char[] buf = new char[65];
if (COMPACT_STRINGS) {
byte[] buf = new byte[65];
int charPos = 64;
boolean negative = (i < 0);
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))];
i = i / radix;
}
buf[charPos] = (byte)Integer.digits[(int)(-i)];
if (negative) {
buf[--charPos] = '-';
}
return StringLatin1.newString(buf, charPos, (65 - charPos));
}
return toStringUTF16(i, radix);
}
private static String toStringUTF16(long i, int radix) {
byte[] buf = new byte[65 * 2];
int charPos = 64;
boolean negative = (i < 0);
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = Integer.digits[(int)(-(i % radix))];
StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]);
i = i / radix;
}
buf[charPos] = Integer.digits[(int)(-i)];
StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]);
if (negative) {
buf[--charPos] = '-';
StringUTF16.putChar(buf, --charPos, '-');
}
return new String(buf, charPos, (65 - charPos));
return StringUTF16.newString(buf, charPos, (65 - charPos));
}
/**
@ -355,10 +379,16 @@ public final class Long extends Number implements Comparable<Long> {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
char[] buf = new char[chars];
formatUnsignedLong(val, shift, buf, 0, chars);
return new String(buf, true);
if (COMPACT_STRINGS) {
byte[] buf = new byte[chars];
formatUnsignedLong0(val, shift, buf, 0, chars);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[chars * 2];
formatUnsignedLong0UTF16(val, shift, buf, 0, chars);
return new String(buf, UTF16);
}
}
/**
@ -385,6 +415,28 @@ public final class Long extends Number implements Comparable<Long> {
} while (charPos > offset);
}
/** byte[]/LATIN1 version */
static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = (byte)Integer.digits[((int) val) & mask];
val >>>= shift;
} while (charPos > offset);
}
/** byte[]/UTF16 version */
static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]);
val >>>= shift;
} while (charPos > offset);
}
/**
* Returns a {@code String} object representing the specified
* {@code long}. The argument is converted to signed decimal
@ -399,9 +451,15 @@ public final class Long extends Number implements Comparable<Long> {
if (i == Long.MIN_VALUE)
return "-9223372036854775808";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
getChars(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
getCharsUTF16(i, size, buf);
return new String(buf, UTF16);
}
}
/**
@ -431,7 +489,7 @@ public final class Long extends Number implements Comparable<Long> {
*
* Will fail if i == Long.MIN_VALUE
*/
static void getChars(long i, int index, char[] buf) {
static void getChars(long i, int index, byte[] buf) {
long q;
int r;
int charPos = index;
@ -448,8 +506,8 @@ public final class Long extends Number implements Comparable<Long> {
// really: r = i - (q * 100);
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
i = q;
buf[--charPos] = Integer.DigitOnes[r];
buf[--charPos] = Integer.DigitTens[r];
buf[--charPos] = (byte)Integer.DigitOnes[r];
buf[--charPos] = (byte)Integer.DigitTens[r];
}
// Get 2 digits/iteration using ints
@ -460,8 +518,8 @@ public final class Long extends Number implements Comparable<Long> {
// really: r = i2 - (q * 100);
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
i2 = q2;
buf[--charPos] = Integer.DigitOnes[r];
buf[--charPos] = Integer.DigitTens[r];
buf[--charPos] = (byte)Integer.DigitOnes[r];
buf[--charPos] = (byte)Integer.DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
@ -469,12 +527,59 @@ public final class Long extends Number implements Comparable<Long> {
for (;;) {
q2 = (i2 * 52429) >>> (16+3);
r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
buf[--charPos] = Integer.digits[r];
buf[--charPos] = (byte)Integer.digits[r];
i2 = q2;
if (i2 == 0) break;
}
if (sign != 0) {
buf[--charPos] = sign;
buf[--charPos] = (byte)sign;
}
}
static void getCharsUTF16(long i, int index, byte[] buf) {
long q;
int r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Get 2 digits/iteration using longs until quotient fits into an int
while (i > Integer.MAX_VALUE) {
q = i / 100;
// really: r = i - (q * 100);
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
i = q;
StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
}
// Get 2 digits/iteration using ints
int q2;
int i2 = (int)i;
while (i2 >= 65536) {
q2 = i2 / 100;
// really: r = i2 - (q * 100);
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
i2 = q2;
StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
}
// Fall thru to fast mode for smaller numbers
// assert(i2 <= 65536, i2);
for (;;) {
q2 = (i2 * 52429) >>> (16+3);
r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
i2 = q2;
if (i2 == 0) break;
}
if (sign != 0) {
StringUTF16.putChar(buf, --charPos, sign);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -104,7 +104,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
private transient String toStringCache;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;
@ -169,15 +169,13 @@ import jdk.internal.HotSpotIntrinsicCandidate;
@Override
public synchronized int capacity() {
return value.length;
return super.capacity();
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
super.ensureCapacity(minimumCapacity);
}
/**
@ -204,9 +202,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
*/
@Override
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
return super.charAt(index);
}
/**
@ -261,10 +257,8 @@ import jdk.internal.HotSpotIntrinsicCandidate;
*/
@Override
public synchronized void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
toStringCache = null;
value[index] = ch;
super.setCharAt(index, ch);
}
@Override
@ -680,9 +674,11 @@ import jdk.internal.HotSpotIntrinsicCandidate;
@HotSpotIntrinsicCandidate
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
return toStringCache =
isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
return new String(toStringCache, true);
return new String(toStringCache);
}
/**
@ -710,7 +706,13 @@ import jdk.internal.HotSpotIntrinsicCandidate;
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
java.io.ObjectOutputStream.PutField fields = s.putFields();
fields.put("value", value);
char[] val = new char[capacity()];
if (isLatin1()) {
StringLatin1.getChars(value, 0, count, val, 0);
} else {
StringUTF16.getChars(value, 0, count, val, 0);
}
fields.put("value", val);
fields.put("count", count);
fields.put("shared", false);
s.writeFields();
@ -723,7 +725,12 @@ import jdk.internal.HotSpotIntrinsicCandidate;
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
java.io.ObjectInputStream.GetField fields = s.readFields();
value = (char[])fields.get("value", null);
char[] val = (char[])fields.get("value", null);
initBytes(val, 0, val.length);
count = fields.get("count", 0);
}
protected synchronized void getBytes(byte dst[], int dstBegin, byte coder) {
super.getBytes(dst, dstBegin, coder);
}
}

View File

@ -412,7 +412,8 @@ public final class StringBuilder
@HotSpotIntrinsicCandidate
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
return isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newStringSB(value, 0, count);
}
/**
@ -430,7 +431,13 @@ public final class StringBuilder
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
char[] val = new char[capacity()];
if (isLatin1()) {
StringLatin1.getChars(value, 0, count, val, 0);
} else {
StringUTF16.getChars(value, 0, count, val, 0);
}
s.writeObject(val);
}
/**
@ -441,7 +448,8 @@ public final class StringBuilder
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject();
char[] val = (char[]) s.readObject();
initBytes(val, 0, val.length);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,11 +38,19 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.misc.MessageUtils;
import sun.nio.cs.HistoricallyNamedCharset;
import sun.nio.cs.ArrayDecoder;
import sun.nio.cs.ArrayEncoder;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static java.lang.String.COMPACT_STRINGS;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Utility class for string encoding and decoding.
*/
@ -72,23 +80,13 @@ class StringCoding {
// Trim the given byte array to the given length
//
private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) {
private static byte[] safeTrim(byte[] ba, int len, boolean isTrusted) {
if (len == ba.length && (isTrusted || System.getSecurityManager() == null))
return ba;
else
return Arrays.copyOf(ba, len);
}
// Trim the given char array to the given length
//
private static char[] safeTrim(char[] ca, int len,
Charset cs, boolean isTrusted) {
if (len == ca.length && (isTrusted || System.getSecurityManager() == null))
return ca;
else
return Arrays.copyOf(ca, len);
}
private static int scale(int len, float expansionFactor) {
// We need to perform double, not float, arithmetic; otherwise
// we lose low order bits when len is larger than 2**24.
@ -117,21 +115,64 @@ class StringCoding {
}
}
static class Result {
byte[] value;
byte coder;
Result with() {
coder = COMPACT_STRINGS ? LATIN1 : UTF16;
value = new byte[0];
return this;
}
Result with(char[] val, int off, int len) {
if (String.COMPACT_STRINGS) {
byte[] bs = StringUTF16.compress(val, off, len);
if (bs != null) {
value = bs;
coder = LATIN1;
return this;
}
}
coder = UTF16;
value = StringUTF16.toBytes(val, off, len);
return this;
}
Result with(byte[] val, byte coder) {
this.coder = coder;
value = val;
return this;
}
}
@HotSpotIntrinsicCandidate
private static boolean hasNegatives(byte[] ba, int off, int len) {
for (int i = off; i < off + len; i++) {
if (ba[i] < 0) {
return true;
}
}
return false;
}
// -- Decoding --
private static class StringDecoder {
static class StringDecoder {
private final String requestedCharsetName;
private final Charset cs;
private final boolean isASCIICompatible;
private final CharsetDecoder cd;
private final boolean isTrusted;
protected final Result result;
private StringDecoder(Charset cs, String rcn) {
StringDecoder(Charset cs, String rcn) {
this.requestedCharsetName = rcn;
this.cs = cs;
this.cd = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
this.isTrusted = (cs.getClass().getClassLoader0() == null);
this.result = new Result();
this.isASCIICompatible = (cd instanceof ArrayDecoder) &&
((ArrayDecoder)cd).isASCIICompatible();
}
String charsetName() {
@ -144,36 +185,58 @@ class StringCoding {
return requestedCharsetName;
}
char[] decode(byte[] ba, int off, int len) {
Result decode(byte[] ba, int off, int len) {
if (len == 0) {
return result.with();
}
// fastpath for ascii compatible
if (isASCIICompatible && !hasNegatives(ba, off, len)) {
if (COMPACT_STRINGS) {
return result.with(Arrays.copyOfRange(ba, off, off + len),
LATIN1);
} else {
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
return result.with(ca, 0, clen);
}
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return result.with(ca, 0, cb.position());
}
}
private static class StringDecoder8859_1 extends StringDecoder {
StringDecoder8859_1(Charset cs, String rcn) {
super(cs, rcn);
}
Result decode(byte[] ba, int off, int len) {
if (COMPACT_STRINGS) {
return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1);
} else {
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
}
static char[] decode(String charsetName, byte[] ba, int off, int len)
static Result decode(String charsetName, byte[] ba, int off, int len)
throws UnsupportedEncodingException
{
StringDecoder sd = deref(decoder);
@ -183,8 +246,15 @@ class StringCoding {
sd = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
sd = new StringDecoder(cs, csn);
if (cs != null) {
if (cs == UTF_8) {
sd = new StringDecoderUTF8(cs, csn);
} else if (cs == ISO_8859_1) {
sd = new StringDecoder8859_1(cs, csn);
} else {
sd = new StringDecoder(cs, csn);
}
}
} catch (IllegalCharsetNameException x) {}
if (sd == null)
throw new UnsupportedEncodingException(csn);
@ -193,7 +263,7 @@ class StringCoding {
return sd.decode(ba, off, len);
}
static char[] decode(Charset cs, byte[] ba, int off, int len) {
static Result decode(Charset cs, byte[] ba, int off, int len) {
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
// de/encode() method. These SD/E objects are short-lived, the young-gen
@ -210,44 +280,57 @@ class StringCoding {
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
// but it then can be argued that the SM is null when the operation
// is started...
if (cs == UTF_8) {
return StringDecoderUTF8.decode(ba, off, len, new Result());
}
CharsetDecoder cd = cs.newDecoder();
// ascii fastpath
if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) &&
((ArrayDecoder)cd).isASCIICompatible() &&
!hasNegatives(ba, off, len))) {
if (COMPACT_STRINGS) {
return new Result().with(Arrays.copyOfRange(ba, off, off + len),
LATIN1);
} else {
return new Result().with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
if (len == 0) {
return new Result().with();
}
if (System.getSecurityManager() != null &&
cs.getClass().getClassLoader0() != null) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
cd.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
char[] ca = new char[en];
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
return new Result().with(ca, 0, clen);
}
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return new Result().with(ca, 0, cb.position());
}
static char[] decode(byte[] ba, int off, int len) {
static Result decode(byte[] ba, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// use charset name decode() variant which provides caching.
@ -273,6 +356,7 @@ class StringCoding {
private static class StringEncoder {
private Charset cs;
private CharsetEncoder ce;
private final boolean isASCIICompatible;
private final String requestedCharsetName;
private final boolean isTrusted;
@ -283,6 +367,8 @@ class StringCoding {
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
this.isTrusted = (cs.getClass().getClassLoader0() == null);
this.isASCIICompatible = (ce instanceof ArrayEncoder) &&
((ArrayEncoder)ce).isASCIICompatible();
}
String charsetName() {
@ -295,36 +381,186 @@ class StringCoding {
return requestedCharsetName;
}
byte[] encode(char[] ca, int off, int len) {
byte[] encode(byte coder, byte[] val) {
// fastpath for ascii compatible
if (coder == LATIN1 && isASCIICompatible &&
!hasNegatives(val, 0, val.length)) {
return Arrays.copyOf(val, val.length);
}
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
if (len == 0) {
return ba;
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
if (ce instanceof ArrayEncoder) {
if (!isTrusted) {
val = Arrays.copyOf(val, val.length);
}
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
if (blen != -1) {
return safeTrim(ba, blen, isTrusted);
}
}
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
: StringUTF16.toChars(val);
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ba, bb.position(), isTrusted);
}
}
static byte[] encode(String charsetName, char[] ca, int off, int len)
@HotSpotIntrinsicCandidate
private static int implEncodeISOArray(byte[] sa, int sp,
byte[] da, int dp, int len) {
int i = 0;
for (; i < len; i++) {
char c = StringUTF16.getChar(sa, sp++);
if (c > '\u00FF')
break;
da[dp++] = (byte)c;
}
return i;
}
static byte[] encode8859_1(byte coder, byte[] val) {
if (coder == LATIN1) {
return Arrays.copyOf(val, val.length);
}
int len = val.length >> 1;
byte[] dst = new byte[len];
int dp = 0;
int sp = 0;
int sl = len;
while (sp < sl) {
int ret = implEncodeISOArray(val, sp, dst, dp, len);
sp = sp + ret;
dp = dp + ret;
if (ret != len) {
char c = StringUTF16.getChar(val, sp++);
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(val, sp))) {
sp++;
}
dst[dp++] = '?';
len = sl - sp;
}
}
if (dp == dst.length) {
return dst;
}
return Arrays.copyOf(dst, dp);
}
static byte[] encodeASCII(byte coder, byte[] val) {
if (coder == LATIN1) {
byte[] dst = new byte[val.length];
for (int i = 0; i < val.length; i++) {
if (val[i] < 0) {
dst[i] = '?';
} else {
dst[i] = val[i];
}
}
return dst;
}
int len = val.length >> 1;
byte[] dst = new byte[len];
int dp = 0;
for (int i = 0; i < len; i++) {
char c = StringUTF16.getChar(val, i);
if (c < 0x80) {
dst[dp++] = (byte)c;
continue;
}
if (Character.isHighSurrogate(c) && i + 1 < len &&
Character.isLowSurrogate(StringUTF16.getChar(val, i + 1))) {
i++;
}
dst[dp++] = '?';
}
if (len == dp) {
return dst;
}
return Arrays.copyOf(dst, dp);
}
static byte[] encodeUTF8(byte coder, byte[] val) {
int dp = 0;
byte[] dst;
if (coder == LATIN1) {
dst = new byte[val.length << 1];
for (int sp = 0; sp < val.length; sp++) {
byte c = val[sp];
if (c < 0) {
dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else {
dst[dp++] = c;
}
}
} else {
int sp = 0;
int sl = val.length >> 1;
dst = new byte[sl * 3];
char c;
while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') {
// ascii fast loop;
dst[dp++] = (byte)c;
sp++;
}
while (sp < sl) {
c = StringUTF16.getChar(val, sp++);
if (c < 0x80) {
dst[dp++] = (byte)c;
} else if (c < 0x800) {
dst[dp++] = (byte)(0xc0 | (c >> 6));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
int uc = -1;
char c2;
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) {
uc = Character.toCodePoint(c, c2);
}
if (uc < 0) {
dst[dp++] = '?';
} else {
dst[dp++] = (byte)(0xf0 | ((uc >> 18)));
dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
}
} else {
// 3 bytes, 16 bits
dst[dp++] = (byte)(0xe0 | ((c >> 12)));
dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
dst[dp++] = (byte)(0x80 | (c & 0x3f));
}
}
}
if (dp == dst.length) {
return dst;
}
return Arrays.copyOf(dst, dp);
}
static byte[] encode(String charsetName, byte coder, byte[] val)
throws UnsupportedEncodingException
{
StringEncoder se = deref(encoder);
@ -334,62 +570,88 @@ class StringCoding {
se = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
if (cs != null) {
if (cs == UTF_8) {
return encodeUTF8(coder, val);
} else if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
} else if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
se = new StringEncoder(cs, csn);
}
} catch (IllegalCharsetNameException x) {}
if (se == null)
if (se == null) {
throw new UnsupportedEncodingException (csn);
}
set(encoder, se);
}
return se.encode(ca, off, len);
return se.encode(coder, val);
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
static byte[] encode(Charset cs, byte coder, byte[] val) {
if (cs == UTF_8) {
return encodeUTF8(coder, val);
} else if (cs == ISO_8859_1) {
return encode8859_1(coder, val);
} else if (cs == US_ASCII) {
return encodeASCII(coder, val);
}
CharsetEncoder ce = cs.newEncoder();
// fastpath for ascii compatible
if (coder == LATIN1 && (((ce instanceof ArrayEncoder) &&
((ArrayEncoder)ce).isASCIICompatible() &&
!hasNegatives(val, 0, val.length)))) {
return Arrays.copyOf(val, val.length);
}
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
if (len == 0) {
return ba;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
}
boolean isTrusted = System.getSecurityManager() == null ||
cs.getClass().getClassLoader0() == null;
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
if (!isTrusted) {
val = Arrays.copyOf(val, val.length);
}
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
if (blen != -1) {
return safeTrim(ba, blen, isTrusted);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
: StringUTF16.toChars(val);
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), isTrusted);
}
static byte[] encode(char[] ca, int off, int len) {
static byte[] encode(byte coder, byte[] val) {
String csn = Charset.defaultCharset().name();
try {
// use charset name encode() variant which provides caching.
return encode(csn, ca, off, len);
return encode(csn, coder, val);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
}
try {
return encode("ISO-8859-1", ca, off, len);
return encode("ISO-8859-1", coder, val);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, MessageUtils is
// the only way we will be able to get any kind of error message.

View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.nio.charset.Charset;
import java.util.Arrays;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.Character.isSurrogate;
import static java.lang.Character.highSurrogate;
import static java.lang.Character.lowSurrogate;
import static java.lang.Character.isSupplementaryCodePoint;
import static java.lang.StringUTF16.putChar;
class StringDecoderUTF8 extends StringCoding.StringDecoder {
StringDecoderUTF8(Charset cs, String rcn) {
super(cs, rcn);
}
private static boolean isNotContinuation(int b) {
return (b & 0xc0) != 0x80;
}
private static boolean isMalformed3(int b1, int b2, int b3) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
}
private static boolean isMalformed3_2(int b1, int b2) {
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
// for nb == 3/4
private static int malformedN(byte[] src, int sp, int nb) {
if (nb == 3) {
int b1 = src[sp++];
int b2 = src[sp++]; // no need to lookup b3
return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
isNotContinuation(b2)) ? 1 : 2;
} else if (nb == 4) { // we don't care the speed here
int b1 = src[sp++] & 0xff;
int b2 = src[sp++] & 0xff;
if (b1 > 0xf4 ||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
isNotContinuation(b2))
return 1;
if (isNotContinuation(src[sp++]))
return 2;
return 3;
}
assert false;
return -1;
}
private static char repl = '\ufffd';
StringCoding.Result decode(byte[] src, int sp, int len) {
return decode(src, sp, len, result);
}
static StringCoding.Result decode(byte[] src, int sp, int len,
StringCoding.Result ret) {
int sl = sp + len;
byte[] dst = new byte[len];
int dp = 0;
if (COMPACT_STRINGS) { // Latin1 only loop
while (sp < sl) {
int b1 = src[sp];
if (b1 >= 0) {
dst[dp++] = (byte)b1;
sp++;
continue;
}
if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) &&
sp + 1 < sl) {
int b2 = src[sp + 1];
if (!isNotContinuation(b2)) {
dst[dp++] = (byte)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0)));
sp += 2;
continue;
}
}
// anything not a latin1, including the repl
// we have to go with the utf16
break;
}
if (sp == sl) {
if (dp != dst.length) {
dst = Arrays.copyOf(dst, dp);
}
return ret.with(dst, LATIN1);
}
}
if (dp == 0) {
dst = new byte[len << 1];
} else {
byte[] buf = new byte[len << 1];
StringLatin1.inflate(dst, 0, buf, 0, dp);
dst = buf;
}
while (sp < sl) {
int b1 = src[sp++];
if (b1 >= 0) {
putChar(dst, dp++, (char) b1);
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
if (sp < sl) {
int b2 = src[sp++];
if (isNotContinuation(b2)) {
putChar(dst, dp++, repl);
sp--;
} else {
putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^
(((byte) 0xC0 << 6) ^
((byte) 0x80 << 0))));
}
continue;
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 4) == -2) {
if (sp + 1 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
if (isMalformed3(b1, b2, b3)) {
putChar(dst, dp++, repl);
sp -= 3;
sp += malformedN(src, sp, 3);
} else {
char c = (char)((b1 << 12) ^
(b2 << 6) ^
(b3 ^
(((byte) 0xE0 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
putChar(dst, dp++, isSurrogate(c) ? repl : c);
}
continue;
}
if (sp < sl && isMalformed3_2(b1, src[sp])) {
putChar(dst, dp++, repl);
continue;
}
putChar(dst, dp++, repl);
break;
} else if ((b1 >> 3) == -2) {
if (sp + 2 < sl) {
int b2 = src[sp++];
int b3 = src[sp++];
int b4 = src[sp++];
int uc = ((b1 << 18) ^
(b2 << 12) ^
(b3 << 6) ^
(b4 ^
(((byte) 0xF0 << 18) ^
((byte) 0x80 << 12) ^
((byte) 0x80 << 6) ^
((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
!isSupplementaryCodePoint(uc)) { // shortest form check
putChar(dst, dp++, repl);
sp -= 4;
sp += malformedN(src, sp, 4);
} else {
putChar(dst, dp++, highSurrogate(uc));
putChar(dst, dp++, lowSurrogate(uc));
}
continue;
}
b1 &= 0xff;
if (b1 > 0xf4 ||
sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) {
putChar(dst, dp++, repl);
continue;
}
sp++;
putChar(dst, dp++, repl);
if (sp < sl && isMalformed4_3(src[sp])) {
continue;
}
break;
} else {
putChar(dst, dp++, repl);
}
}
if (dp != len) {
dst = Arrays.copyOf(dst, dp << 1);
}
return ret.with(dst, UTF16);
}
}

View File

@ -0,0 +1,600 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import jdk.internal.HotSpotIntrinsicCandidate;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static java.lang.String.checkOffset;
final class StringLatin1 {
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
public static boolean canEncode(int cp) {
return cp >>> 8 == 0;
}
public static int length(byte[] value) {
return value.length;
}
public static int codePointAt(byte[] value, int index, int end) {
return value[index] & 0xff;
}
public static int codePointBefore(byte[] value, int index) {
return value[index - 1] & 0xff;
}
public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
return endIndex - beginIndex;
}
public static char[] toChars(byte[] value) {
char[] dst = new char[value.length];
inflate(value, 0, dst, 0, value.length);
return dst;
}
public static byte[] inflate(byte[] value, int off, int len) {
byte[] ret = StringUTF16.newBytesFor(len);
inflate(value, off, ret, 0, len);
return ret;
}
public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
@HotSpotIntrinsicCandidate
public static int compareTo(byte[] value, byte[] other) {
int len1 = value.length;
int len2 = other.length;
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
if (value[k] != other[k]) {
return getChar(value, k) - getChar(other, k);
}
}
return len1 - len2;
}
@HotSpotIntrinsicCandidate
public static int compareToUTF16(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = StringUTF16.length(other);
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
char c2 = StringUTF16.getChar(other, k);
if (c1 != c2) {
return c1 - c2;
}
}
return len1 - len2;
}
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
public static int indexOf(byte[] value, int ch, int fromIndex) {
if (!canEncode(ch)) {
return -1;
}
int max = value.length;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= max) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
byte c = (byte)ch;
for (int i = fromIndex; i < max; i++) {
if (value[i] == c) {
return i;
}
}
return -1;
}
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, byte[] str) {
if (str.length == 0) {
return 0;
}
if (value.length == 0) {
return -1;
}
return indexOf(value, value.length, str, str.length, 0);
}
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
byte first = str[0];
int max = (valueCount - strCount);
for (int i = fromIndex; i <= max; i++) {
// Look for first character.
if (value[i] != first) {
while (++i <= max && value[i] != first);
}
// Found first character, now look at the rest of value
if (i <= max) {
int j = i + 1;
int end = j + strCount - 1;
for (int k = 1; j < end && value[j] == str[k]; j++, k++);
if (j == end) {
// Found whole string.
return i;
}
}
}
return -1;
}
public static int lastIndexOf(byte[] src, int srcCount,
byte[] tgt, int tgtCount, int fromIndex) {
int min = tgtCount - 1;
int i = min + fromIndex;
int strLastIndex = tgtCount - 1;
char strLastChar = (char)(tgt[strLastIndex] & 0xff);
startSearchForLastChar:
while (true) {
while (i >= min && (src[i] & 0xff) != strLastChar) {
i--;
}
if (i < min) {
return -1;
}
int j = i - 1;
int start = j - strLastIndex;
int k = strLastIndex - 1;
while (j > start) {
if ((src[j--] & 0xff) != (tgt[k--] & 0xff)) {
i--;
continue startSearchForLastChar;
}
}
return start + 1;
}
}
public static int lastIndexOf(final byte[] value, int ch, int fromIndex) {
if (!canEncode(ch)) {
return -1;
}
int off = Math.min(fromIndex, value.length - 1);
for (; off >= 0; off--) {
if (value[off] == (byte)ch) {
return off;
}
}
return -1;
}
public static String replace(byte[] value, char oldChar, char newChar) {
if (canEncode(oldChar)) {
int len = value.length;
int i = -1;
while (++i < len) {
if (value[i] == (byte)oldChar) {
break;
}
}
if (i < len) {
if (canEncode(newChar)) {
byte buf[] = new byte[len];
for (int j = 0; j < i; j++) { // TBD arraycopy?
buf[j] = value[j];
}
while (i < len) {
byte c = value[i];
buf[i] = (c == (byte)oldChar) ? (byte)newChar : c;
i++;
}
return new String(buf, LATIN1);
} else {
byte[] buf = StringUTF16.newBytesFor(len);
// inflate from latin1 to UTF16
inflate(value, 0, buf, 0, i);
while (i < len) {
char c = (char)(value[i] & 0xff);
StringUTF16.putChar(buf, i, (c == oldChar) ? newChar : c);
i++;
}
return new String(buf, UTF16);
}
}
}
return null; // for string to return this;
}
// case insensitive
public static boolean regionMatchesCI(byte[] value, int toffset,
byte[] other, int ooffset, int len) {
int last = toffset + len;
while (toffset < last) {
char c1 = (char)(value[toffset++] & 0xff);
char c2 = (char)(other[ooffset++] & 0xff);
if (c1 == c2) {
continue;
}
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
return false;
}
return true;
}
public static boolean regionMatchesCI_UTF16(byte[] value, int toffset,
byte[] other, int ooffset, int len) {
int last = toffset + len;
while (toffset < last) {
char c1 = (char)(value[toffset++] & 0xff);
char c2 = StringUTF16.getChar(other, ooffset++);
if (c1 == c2) {
continue;
}
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
return false;
}
return true;
}
public static String toLowerCase(String str, byte[] value, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int first;
final int len = value.length;
// Now check if there are any characters that need to be changed, or are surrogate
for (first = 0 ; first < len; first++) {
int cp = value[first] & 0xff;
if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR
break;
}
}
if (first == len)
return str;
String lang = locale.getLanguage();
if (lang == "tr" || lang == "az" || lang == "lt") {
return toLowerCaseEx(str, value, first, locale, true);
}
byte[] result = new byte[len];
System.arraycopy(value, 0, result, 0, first); // Just copy the first few
// lowerCase characters.
for (int i = first; i < len; i++) {
int cp = value[i] & 0xff;
cp = Character.toLowerCase(cp);
if (!canEncode(cp)) { // not a latin1 character
return toLowerCaseEx(str, value, first, locale, false);
}
result[i] = (byte)cp;
}
return new String(result, LATIN1);
}
private static String toLowerCaseEx(String str, byte[] value,
int first, Locale locale, boolean localeDependent)
{
byte[] result = StringUTF16.newBytesFor(value.length);
int resultOffset = 0;
for (int i = 0; i < first; i++) {
StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
}
for (int i = first; i < value.length; i++) {
int srcChar = value[i] & 0xff;
int lowerChar;
char[] lowerCharArray;
if (localeDependent) {
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
} else {
lowerChar = Character.toLowerCase(srcChar);
}
if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp
StringUTF16.putChar(result, resultOffset++, lowerChar);
} else {
if (lowerChar == Character.ERROR) {
lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
} else {
lowerCharArray = Character.toChars(lowerChar);
}
/* Grow result if needed */
int mapLen = lowerCharArray.length;
if (mapLen > 1) {
byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
StringUTF16.putChar(result, resultOffset++, lowerCharArray[x]);
}
}
}
return StringUTF16.newString(result, 0, resultOffset);
}
public static String toUpperCase(String str, byte[] value, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int first;
final int len = value.length;
// Now check if there are any characters that need to be changed, or are surrogate
for (first = 0 ; first < len; first++ ) {
int cp = value[first] & 0xff;
if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR
break;
}
}
if (first == len) {
return str;
}
String lang = locale.getLanguage();
if (lang == "tr" || lang == "az" || lang == "lt") {
return toUpperCaseEx(str, value, first, locale, true);
}
byte[] result = new byte[len];
System.arraycopy(value, 0, result, 0, first); // Just copy the first few
// upperCase characters.
for (int i = first; i < len; i++) {
int cp = value[i] & 0xff;
cp = Character.toUpperCaseEx(cp);
if (!canEncode(cp)) { // not a latin1 character
return toUpperCaseEx(str, value, first, locale, false);
}
result[i] = (byte)cp;
}
return new String(result, LATIN1);
}
private static String toUpperCaseEx(String str, byte[] value,
int first, Locale locale, boolean localeDependent)
{
byte[] result = StringUTF16.newBytesFor(value.length);
int resultOffset = 0;
for (int i = 0; i < first; i++) {
StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
}
for (int i = first; i < value.length; i++) {
int srcChar = value[i] & 0xff;
int upperChar;
char[] upperCharArray;
if (localeDependent) {
upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
} else {
upperChar = Character.toUpperCaseEx(srcChar);
}
if (Character.isBmpCodePoint(upperChar)) {
StringUTF16.putChar(result, resultOffset++, upperChar);
} else {
if (upperChar == Character.ERROR) {
if (localeDependent) {
upperCharArray =
ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
} else {
upperCharArray = Character.toUpperCaseCharArray(srcChar);
}
} else {
upperCharArray = Character.toChars(upperChar);
}
/* Grow result if needed */
int mapLen = upperCharArray.length;
if (mapLen > 1) {
byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
StringUTF16.putChar(result, resultOffset++, upperCharArray[x]);
}
}
}
return StringUTF16.newString(result, 0, resultOffset);
}
public static String trim(byte[] value) {
int len = value.length;
int st = 0;
while ((st < len) && ((value[st] & 0xff) <= ' ')) {
st++;
}
while ((st < len) && ((value[len - 1] & 0xff) <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ?
newString(value, st, len - st) : null;
}
public static void putChar(byte[] val, int index, int c) {
//assert (canEncode(c));
val[index] = (byte)(c);
}
public static char getChar(byte[] val, int index) {
return (char)(val[index] & 0xff);
}
public static byte[] toBytes(int[] val, int off, int len) {
byte[] ret = new byte[len];
for (int i = 0; i < len; i++) {
int cp = val[off++];
if (!canEncode(cp)) {
return null;
}
ret[i] = (byte)cp;
}
return ret;
}
public static byte[] toBytes(char c) {
return new byte[] { (byte)c };
}
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len),
LATIN1);
}
public static void fillNull(byte[] val, int index, int end) {
Arrays.fill(val, index, end, (byte)0);
}
// inflatedCopy byte[] -> char[]
@HotSpotIntrinsicCandidate
private static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
dst[dstOff++] = (char)(src[srcOff++] & 0xff);
}
}
// inflatedCopy byte[] -> byte[]
@HotSpotIntrinsicCandidate
public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
StringUTF16.putChar(dst, dstOff++, src[srcOff++] & 0xff);
}
}
static class CharsSpliterator implements Spliterator.OfInt {
private final byte[] array;
private int index; // current index, modified on advance/split
private final int fence; // one past last index
private final int cs;
CharsSpliterator(byte[] array, int acs) {
this(array, 0, array.length, acs);
}
CharsSpliterator(byte[] array, int origin, int fence, int acs) {
this.array = array;
this.index = origin;
this.fence = fence;
this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
| Spliterator.SUBSIZED;
}
@Override
public OfInt trySplit() {
int lo = index, mid = (lo + fence) >>> 1;
return (lo >= mid)
? null
: new CharsSpliterator(array, lo, index = mid, cs);
}
@Override
public void forEachRemaining(IntConsumer action) {
byte[] a; int i, hi; // hoist accesses and checks from loop
if (action == null)
throw new NullPointerException();
if ((a = array).length >= (hi = fence) &&
(i = index) >= 0 && i < (index = hi)) {
do { action.accept(a[i] & 0xff); } while (++i < hi);
}
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null)
throw new NullPointerException();
if (index >= 0 && index < fence) {
action.accept(array[index++] & 0xff);
return true;
}
return false;
}
@Override
public long estimateSize() { return (long)(fence - index); }
@Override
public int characteristics() {
return cs;
}
}
////////////////////////////////////////////////////////////////
public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
checkOffset(srcEnd, val.length);
getChars(val, srcBegin, srcEnd, dst, dstBegin);
}
public static void inflateSB(byte[] val, byte[] dst, int dstOff, int count) {
checkOffset(count, val.length);
checkOffset(dstOff + count, dst.length >> 1); // dst is utf16
inflate(val, 0, dst, dstOff, count);
}
}

View File

@ -0,0 +1,971 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.util.Arrays;
import java.util.Locale;
import java.util.Spliterator;
import java.util.function.IntConsumer;
import jdk.internal.HotSpotIntrinsicCandidate;
import static java.lang.String.UTF16;
import static java.lang.String.LATIN1;
import static java.lang.String.checkIndex;
import static java.lang.String.checkOffset;
final class StringUTF16 {
public static byte[] newBytesFor(int len) {
if (len < 0) {
throw new NegativeArraySizeException();
}
if (len > MAX_LENGTH) {
throw new OutOfMemoryError("UTF16 String size is " + len +
", should be less than " + MAX_LENGTH);
}
return new byte[len << 1];
}
@HotSpotIntrinsicCandidate
public static void putChar(byte[] val, int index, int c) {
index <<= 1;
val[index++] = (byte)(c >> HI_BYTE_SHIFT);
val[index] = (byte)(c >> LO_BYTE_SHIFT);
}
@HotSpotIntrinsicCandidate
public static char getChar(byte[] val, int index) {
index <<= 1;
return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
((val[index] & 0xff) << LO_BYTE_SHIFT));
}
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length >> 1) {
throw new StringIndexOutOfBoundsException(index);
}
return getChar(value, index);
}
public static int length(byte[] value) {
return value.length >> 1;
}
public static int codePointAt(byte[] value, int index, int end) {
char c1 = getChar(value, index);
if (Character.isHighSurrogate(c1) && ++index < end) {
char c2 = getChar(value, index);
if (Character.isLowSurrogate(c2)) {
return Character.toCodePoint(c1, c2);
}
}
return c1;
}
public static int codePointBefore(byte[] value, int index) {
char c2 = getChar(value, --index);
if (Character.isLowSurrogate(c2) && index > 0) {
char c1 = getChar(value, --index);
if (Character.isHighSurrogate(c1)) {
return Character.toCodePoint(c1, c2);
}
}
return c2;
}
public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
int count = endIndex - beginIndex;
for (int i = beginIndex; i < endIndex; ) {
if (Character.isHighSurrogate(getChar(value, i++)) &&
i < endIndex &&
Character.isLowSurrogate(getChar(value, i))) {
count--;
i++;
}
}
return count;
}
public static char[] toChars(byte[] value) {
char[] dst = new char[value.length >> 1];
getChars(value, 0, dst.length, dst, 0);
return dst;
}
@HotSpotIntrinsicCandidate
public static byte[] toBytes(char[] value, int off, int len) {
byte[] val = newBytesFor(len);
for (int i = 0; i < len; i++) {
putChar(val, i, value[off++]);
}
return val;
}
public static byte[] compress(char[] val, int off, int len) {
byte[] ret = new byte[len];
if (compress(val, off, ret, 0, len) == len) {
return ret;
}
return null;
}
public static byte[] compress(byte[] val, int off, int len) {
byte[] ret = new byte[len];
if (compress(val, off, ret, 0, len) == len) {
return ret;
}
return null;
}
// compressedCopy char[] -> byte[]
@HotSpotIntrinsicCandidate
private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
int c = src[srcOff++];
if (c >>> 8 != 0) {
return 0;
}
dst[dstOff++] = (byte)c;
}
return len;
}
// compressedCopy byte[] -> byte[]
@HotSpotIntrinsicCandidate
public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
for (int i = 0; i < len; i++) {
int c = getChar(src, srcOff++);
if (c >>> 8 != 0) {
return 0;
}
dst[dstOff++] = (byte)c;
}
return len;
}
public static byte[] toBytes(int[] val, int index, int len) {
final int end = index + len;
// Pass 1: Compute precise size of char[]
int n = len;
for (int i = index; i < end; i++) {
int cp = val[i];
if (Character.isBmpCodePoint(cp))
continue;
else if (Character.isValidCodePoint(cp))
n++;
else throw new IllegalArgumentException(Integer.toString(cp));
}
// Pass 2: Allocate and fill in <high, low> pair
byte[] buf = newBytesFor(n);
for (int i = index, j = 0; i < end; i++, j++) {
int cp = val[i];
if (Character.isBmpCodePoint(cp)) {
putChar(buf, j, cp);
} else {
putChar(buf, j++, Character.highSurrogate(cp));
putChar(buf, j, Character.lowSurrogate(cp));
}
}
return buf;
}
public static byte[] toBytes(char c) {
byte[] result = new byte[2];
putChar(result, 0, c);
return result;
}
@HotSpotIntrinsicCandidate
public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
for (int i = srcBegin; i < srcEnd; i++) {
dst[dstBegin++] = getChar(value, i);
}
}
/* @see java.lang.String.getBytes(int, int, byte[], int) */
public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
srcBegin <<= 1;
srcEnd <<= 1;
for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
dst[dstBegin++] = value[i];
}
}
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
int len = value.length >> 1;
for (int i = 0; i < len; i++) {
if (getChar(value, i) != getChar(other, i)) {
return false;
}
}
return true;
}
return false;
}
@HotSpotIntrinsicCandidate
public static int compareTo(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = length(other);
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
char c2 = getChar(other, k);
if (c1 != c2) {
return c1 - c2;
}
}
return len1 - len2;
}
@HotSpotIntrinsicCandidate
public static int compareToLatin1(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = StringLatin1.length(other);
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
char c2 = StringLatin1.getChar(other, k);
if (c1 != c2) {
return c1 - c2;
}
}
return len1 - len2;
}
public static int hashCode(byte[] value) {
int h = 0;
int length = value.length >> 1;
for (int i = 0; i < length; i++) {
h = 31 * h + getChar(value, i);
}
return h;
}
public static int indexOf(byte[] value, int ch, int fromIndex) {
int max = value.length >> 1;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= max) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
return indexOfChar(value, ch, fromIndex, max);
} else {
return indexOfSupplementary(value, ch, fromIndex, max);
}
}
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, byte[] str) {
if (str.length == 0) {
return 0;
}
if (value.length == 0) {
return -1;
}
return indexOf(value, length(value), str, length(str), 0);
}
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
char first = getChar(str, 0);
int max = (valueCount - strCount);
for (int i = fromIndex; i <= max; i++) {
// Look for first character.
if (getChar(value, i) != first) {
while (++i <= max && getChar(value, i) != first);
}
// Found first character, now look at the rest of value
if (i <= max) {
int j = i + 1;
int end = j + strCount - 1;
for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
if (j == end) {
// Found whole string.
return i;
}
}
}
return -1;
}
/**
* Handles indexOf Latin1 substring in UTF16 string.
*/
@HotSpotIntrinsicCandidate
public static int indexOfLatin1(byte[] value, byte[] str) {
if (str.length == 0) {
return 0;
}
if (value.length == 0) {
return -1;
}
return indexOfLatin1(value, length(value), str, str.length, 0);
}
@HotSpotIntrinsicCandidate
public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
char first = (char)(tgt[0] & 0xff);
int max = (srcCount - tgtCount);
for (int i = fromIndex; i <= max; i++) {
// Look for first character.
if (getChar(src, i) != first) {
while (++i <= max && getChar(src, i) != first);
}
// Found first character, now look at the rest of v2
if (i <= max) {
int j = i + 1;
int end = j + tgtCount - 1;
for (int k = 1;
j < end && getChar(src, j) == (tgt[k] & 0xff);
j++, k++);
if (j == end) {
// Found whole string.
return i;
}
}
}
return -1;
}
@HotSpotIntrinsicCandidate
private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
for (int i = fromIndex; i < max; i++) {
if (getChar(value, i) == ch) {
return i;
}
}
return -1;
}
/**
* Handles (rare) calls of indexOf with a supplementary character.
*/
private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
if (Character.isValidCodePoint(ch)) {
final char hi = Character.highSurrogate(ch);
final char lo = Character.lowSurrogate(ch);
for (int i = fromIndex; i < max - 1; i++) {
if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
return i;
}
}
}
return -1;
}
public static int lastIndexOf(byte[] src, int srcCount,
byte[] tgt, int tgtCount, int fromIndex) {
int min = tgtCount - 1;
int i = min + fromIndex;
int strLastIndex = tgtCount - 1;
char strLastChar = getChar(tgt, strLastIndex);
startSearchForLastChar:
while (true) {
while (i >= min && getChar(src, i) != strLastChar) {
i--;
}
if (i < min) {
return -1;
}
int j = i - 1;
int start = j - strLastIndex;
int k = strLastIndex - 1;
while (j > start) {
if (getChar(src, j--) != getChar(tgt, k--)) {
i--;
continue startSearchForLastChar;
}
}
return start + 1;
}
}
public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
int i = Math.min(fromIndex, (value.length >> 1) - 1);
for (; i >= 0; i--) {
if (getChar(value, i) == ch) {
return i;
}
}
return -1;
} else {
return lastIndexOfSupplementary(value, ch, fromIndex);
}
}
/**
* Handles (rare) calls of lastIndexOf with a supplementary character.
*/
private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
char hi = Character.highSurrogate(ch);
char lo = Character.lowSurrogate(ch);
int i = Math.min(fromIndex, (value.length >> 1) - 2);
for (; i >= 0; i--) {
if (getChar(value, i) == hi && getChar(value, i + 1) == lo) {
return i;
}
}
}
return -1;
}
public static String replace(byte[] value, char oldChar, char newChar) {
int len = value.length >> 1;
int i = -1;
while (++i < len) {
if (getChar(value, i) == oldChar) {
break;
}
}
if (i < len) {
byte buf[] = new byte[value.length];
for (int j = 0; j < i; j++) {
putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
}
while (i < len) {
char c = getChar(value, i);
putChar(buf, i, c == oldChar ? newChar : c);
i++;
}
// Check if we should try to compress to latin1
if (String.COMPACT_STRINGS &&
!StringLatin1.canEncode(oldChar) &&
StringLatin1.canEncode(newChar)) {
byte[] val = compress(buf, 0, len);
if (val != null) {
return new String(val, LATIN1);
}
}
return new String(buf, UTF16);
}
return null;
}
public static boolean regionMatchesCI(byte[] value, int toffset,
byte[] other, int ooffset, int len) {
int last = toffset + len;
while (toffset < last) {
char c1 = getChar(value, toffset++);
char c2 = getChar(other, ooffset++);
if (c1 == c2) {
continue;
}
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
return false;
}
return true;
}
public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
byte[] other, int ooffset,
int len) {
int last = toffset + len;
while (toffset < last) {
char c1 = getChar(value, toffset++);
char c2 = (char)(other[ooffset++] & 0xff);
if (c1 == c2) {
continue;
}
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
return false;
}
return true;
}
public static String toLowerCase(String str, byte[] value, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int first;
boolean hasSurr = false;
final int len = value.length >> 1;
// Now check if there are any characters that need to be changed, or are surrogate
for (first = 0 ; first < len; first++) {
int cp = (int)getChar(value, first);
if (Character.isSurrogate((char)cp)) {
hasSurr = true;
break;
}
if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR
break;
}
}
if (first == len)
return str;
byte[] result = new byte[value.length];
System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
// lowerCase characters.
String lang = locale.getLanguage();
if (lang == "tr" || lang == "az" || lang == "lt") {
return toLowerCaseEx(str, value, result, first, locale, true);
}
if (hasSurr) {
return toLowerCaseEx(str, value, result, first, locale, false);
}
int bits = 0;
for (int i = first; i < len; i++) {
int cp = (int)getChar(value, i);
if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
Character.isSurrogate((char)cp)) {
return toLowerCaseEx(str, value, result, i, locale, false);
}
if (cp == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
return toLowerCaseEx(str, value, result, i, locale, true);
}
cp = Character.toLowerCase(cp);
if (!Character.isBmpCodePoint(cp)) {
return toLowerCaseEx(str, value, result, i, locale, false);
}
bits |= cp;
putChar(result, i, cp);
}
if (bits >>> 8 != 0) {
return new String(result, UTF16);
} else {
return newString(result, 0, len);
}
}
private static String toLowerCaseEx(String str, byte[] value,
byte[] result, int first, Locale locale,
boolean localeDependent) {
int resultOffset = first;
int length = value.length >> 1;
int srcCount;
for (int i = first; i < length; i += srcCount) {
int srcChar = getChar(value, i);
int lowerChar;
char[] lowerCharArray;
srcCount = 1;
if (Character.isSurrogate((char)srcChar)) {
srcChar = codePointAt(value, i, length);
srcCount = Character.charCount(srcChar);
}
if (localeDependent ||
srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
} else {
lowerChar = Character.toLowerCase(srcChar);
}
if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp
putChar(result, resultOffset++, lowerChar);
} else {
if (lowerChar == Character.ERROR) {
lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
} else {
lowerCharArray = Character.toChars(lowerChar);
}
/* Grow result if needed */
int mapLen = lowerCharArray.length;
if (mapLen > srcCount) {
byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
putChar(result, resultOffset++, lowerCharArray[x]);
}
}
}
return newString(result, 0, resultOffset);
}
public static String toUpperCase(String str, byte[] value, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int first;
boolean hasSurr = false;
final int len = value.length >> 1;
// Now check if there are any characters that need to be changed, or are surrogate
for (first = 0 ; first < len; first++) {
int cp = (int)getChar(value, first);
if (Character.isSurrogate((char)cp)) {
hasSurr = true;
break;
}
if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR
break;
}
}
if (first == len) {
return str;
}
byte[] result = new byte[value.length];
System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
// upperCase characters.
String lang = locale.getLanguage();
if (lang == "tr" || lang == "az" || lang == "lt") {
return toUpperCaseEx(str, value, result, first, locale, true);
}
if (hasSurr) {
return toUpperCaseEx(str, value, result, first, locale, false);
}
int bits = 0;
for (int i = first; i < len; i++) {
int cp = (int)getChar(value, i);
if (Character.isSurrogate((char)cp)) {
return toUpperCaseEx(str, value, result, i, locale, false);
}
cp = Character.toUpperCaseEx(cp);
if (!Character.isBmpCodePoint(cp)) { // Character.ERROR is not bmp
return toUpperCaseEx(str, value, result, i, locale, false);
}
bits |= cp;
putChar(result, i, cp);
}
if (bits >>> 8 != 0) {
return new String(result, UTF16);
} else {
return newString(result, 0, len);
}
}
private static String toUpperCaseEx(String str, byte[] value,
byte[] result, int first,
Locale locale, boolean localeDependent)
{
int resultOffset = first;
int length = value.length >> 1;
int srcCount;
for (int i = first; i < length; i += srcCount) {
int srcChar = getChar(value, i);
int upperChar;
char[] upperCharArray;
srcCount = 1;
if (Character.isSurrogate((char)srcChar)) {
srcChar = codePointAt(value, i, length);
srcCount = Character.charCount(srcChar);
}
if (localeDependent) {
upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
} else {
upperChar = Character.toUpperCaseEx(srcChar);
}
if (Character.isBmpCodePoint(upperChar)) {
putChar(result, resultOffset++, upperChar);
} else {
if (upperChar == Character.ERROR) {
if (localeDependent) {
upperCharArray =
ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
} else {
upperCharArray = Character.toUpperCaseCharArray(srcChar);
}
} else {
upperCharArray = Character.toChars(upperChar);
}
/* Grow result if needed */
int mapLen = upperCharArray.length;
if (mapLen > srcCount) {
byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
putChar(result, resultOffset++, upperCharArray[x]);
}
}
}
return newString(result, 0, resultOffset);
}
public static String trim(byte[] value) {
int length = value.length >> 1;
int len = length;
int st = 0;
while (st < len && getChar(value, st) <= ' ') {
st++;
}
while (st < len && getChar(value, len - 1) <= ' ') {
len--;
}
return ((st > 0) || (len < length )) ?
new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
null;
}
public static void putChars(byte[] val, int index, char[] str, int off, int end) {
while (off < end) {
putChar(val, index++, str[off++]);
}
}
public static String newString(byte[] val, int index, int len) {
if (String.COMPACT_STRINGS) {
byte[] buf = compress(val, index, len);
if (buf != null) {
return new String(buf, LATIN1);
}
}
int last = index + len;
return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
}
public static void fillNull(byte[] val, int index, int end) {
Arrays.fill(val, index << 1, end << 1, (byte)0);
}
static class CharsSpliterator implements Spliterator.OfInt {
private final byte[] array;
private int index; // current index, modified on advance/split
private final int fence; // one past last index
private final int cs;
CharsSpliterator(byte[] array, int acs) {
this(array, 0, array.length >> 1, acs);
}
CharsSpliterator(byte[] array, int origin, int fence, int acs) {
this.array = array;
this.index = origin;
this.fence = fence;
this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
| Spliterator.SUBSIZED;
}
@Override
public OfInt trySplit() {
int lo = index, mid = (lo + fence) >>> 1;
return (lo >= mid)
? null
: new CharsSpliterator(array, lo, index = mid, cs);
}
@Override
public void forEachRemaining(IntConsumer action) {
byte[] a; int i, hi; // hoist accesses and checks from loop
if (action == null)
throw new NullPointerException();
if (((a = array).length >> 1) >= (hi = fence) &&
(i = index) >= 0 && i < (index = hi)) {
do { action.accept(getChar(a, i)); } while (++i < hi);
}
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null)
throw new NullPointerException();
if (index >= 0 && index < fence) {
action.accept(getChar(array, index++));
return true;
}
return false;
}
@Override
public long estimateSize() { return (long)(fence - index); }
@Override
public int characteristics() {
return cs;
}
}
static class CodePointsSpliterator implements Spliterator.OfInt {
private final byte[] array;
private int index; // current index, modified on advance/split
private final int fence; // one past last index
private final int cs;
CodePointsSpliterator(byte[] array, int acs) {
this(array, 0, array.length >> 1, acs);
}
CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
this.array = array;
this.index = origin;
this.fence = fence;
this.cs = acs | Spliterator.ORDERED;
}
@Override
public OfInt trySplit() {
int lo = index, mid = (lo + fence) >>> 1;
if (lo >= mid)
return null;
int midOneLess;
// If the mid-point intersects a surrogate pair
if (Character.isLowSurrogate(getChar(array, mid)) &&
Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) {
// If there is only one pair it cannot be split
if (lo >= midOneLess)
return null;
// Shift the mid-point to align with the surrogate pair
return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
}
return new CodePointsSpliterator(array, lo, index = mid, cs);
}
@Override
public void forEachRemaining(IntConsumer action) {
byte[] a; int i, hi; // hoist accesses and checks from loop
if (action == null)
throw new NullPointerException();
if (((a = array).length >> 1) >= (hi = fence) &&
(i = index) >= 0 && i < (index = hi)) {
do {
i = advance(a, i, hi, action);
} while (i < hi);
}
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null)
throw new NullPointerException();
if (index >= 0 && index < fence) {
index = advance(array, index, fence, action);
return true;
}
return false;
}
// Advance one code point from the index, i, and return the next
// index to advance from
private static int advance(byte[] a, int i, int hi, IntConsumer action) {
char c1 = getChar(a, i++);
int cp = c1;
if (Character.isHighSurrogate(c1) && i < hi) {
char c2 = getChar(a, i);
if (Character.isLowSurrogate(c2)) {
i++;
cp = Character.toCodePoint(c1, c2);
}
}
action.accept(cp);
return i;
}
@Override
public long estimateSize() { return (long)(fence - index); }
@Override
public int characteristics() {
return cs;
}
}
////////////////////////////////////////////////////////////////
public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
checkOffset(srcEnd, val.length >> 1);
getChars(val, srcBegin, srcEnd, dst, dstBegin);
}
public static void putCharSB(byte[] val, int index, int c) {
checkIndex(index, val.length >> 1);
putChar(val, index, c);
}
public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
checkOffset(index + end - off, val.length >> 1);
putChars(val, index, ca, off, end);
}
public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
checkOffset(index + end - off, val.length >> 1);
for (int i = off; i < end; i++) {
putChar(val, index++, s.charAt(i));
}
}
public static int codePointAtSB(byte[] val, int index, int end) {
checkOffset(end, val.length >> 1);
return codePointAt(val, index, end);
}
public static int codePointBeforeSB(byte[] val, int index) {
checkOffset(index, val.length >> 1);
return codePointBefore(val, index);
}
public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
checkOffset(endIndex, val.length >> 1);
return codePointCount(val, beginIndex, endIndex);
}
public static String newStringSB(byte[] val, int index, int len) {
checkOffset(index + len, val.length >> 1);
return newString(val, index, len);
}
////////////////////////////////////////////////////////////////
private static native boolean isBigEndian();
static final int HI_BYTE_SHIFT;
static final int LO_BYTE_SHIFT;
static {
if (isBigEndian()) {
HI_BYTE_SHIFT = 8;
LO_BYTE_SHIFT = 0;
} else {
HI_BYTE_SHIFT = 0;
LO_BYTE_SHIFT = 8;
}
}
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
}

View File

@ -2685,6 +2685,7 @@ public class Arrays {
* @param a2 the other array to be tested for equality
* @return {@code true} if the two arrays are equal
*/
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] a, byte[] a2) {
if (a==a2)
return true;

View File

@ -32,4 +32,8 @@ package sun.nio.cs;
public interface ArrayDecoder {
int decode(byte[] src, int off, int len, char[] dst);
default boolean isASCIICompatible() {
return false;
}
}

View File

@ -26,10 +26,24 @@
package sun.nio.cs;
/*
* FastPath char[]->byte[] encoder, REPLACE on malformed input or
* FastPath char[]/byte[] -> byte[] encoder, REPLACE on malformed input or
* unmappable input.
*/
public interface ArrayEncoder {
// is only used by j.u.zip.ZipCoder for utf8
int encode(char[] src, int off, int len, byte[] dst);
default int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
return -1;
}
default int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
return -1;
}
default boolean isASCIICompatible() {
return false;
}
}

View File

@ -115,6 +115,7 @@ public class DoubleByte {
final char[] b2cSB;
final int b2Min;
final int b2Max;
final boolean isASCIICompatible;
// for SimpleEUC override
protected CoderResult crMalformedOrUnderFlow(int b) {
@ -132,16 +133,23 @@ public class DoubleByte {
public Decoder(Charset cs, float avgcpb, float maxcpb,
char[][] b2c, char[] b2cSB,
int b2Min, int b2Max) {
int b2Min, int b2Max,
boolean isASCIICompatible) {
super(cs, avgcpb, maxcpb);
this.b2c = b2c;
this.b2cSB = b2cSB;
this.b2Min = b2Min;
this.b2Max = b2Max;
this.isASCIICompatible = isASCIICompatible;
}
public Decoder(Charset cs, char[][] b2c, char[] b2cSB, int b2Min, int b2Max,
boolean isASCIICompatible) {
this(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max, isASCIICompatible);
}
public Decoder(Charset cs, char[][] b2c, char[] b2cSB, int b2Min, int b2Max) {
this(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max);
this(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max, false);
}
protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
@ -215,6 +223,7 @@ public class DoubleByte {
return decodeBufferLoop(src, dst);
}
@Override
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
int sl = sp + len;
@ -230,12 +239,12 @@ public class DoubleByte {
if (b2c[b1] == B2C_UNMAPPABLE || // isNotLeadingByte
b2c[b2] != B2C_UNMAPPABLE || // isLeadingByte
decodeSingle(b2) != UNMAPPABLE_DECODING) {
sp--;
sp--;
}
}
}
if (c == UNMAPPABLE_DECODING) {
c = repl;
c = repl;
}
}
dst[dp++] = c;
@ -243,6 +252,11 @@ public class DoubleByte {
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
public void implReset() {
super.implReset();
}
@ -274,8 +288,14 @@ public class DoubleByte {
private int currentState;
public Decoder_EBCDIC(Charset cs,
char[][] b2c, char[] b2cSB, int b2Min, int b2Max) {
super(cs, b2c, b2cSB, b2Min, b2Max);
char[][] b2c, char[] b2cSB, int b2Min, int b2Max,
boolean isASCIICompatible) {
super(cs, b2c, b2cSB, b2Min, b2Max, isASCIICompatible);
}
public Decoder_EBCDIC(Charset cs,
char[][] b2c, char[] b2cSB, int b2Min, int b2Max) {
super(cs, b2c, b2cSB, b2Min, b2Max, false);
}
public void implReset() {
@ -403,6 +423,7 @@ public class DoubleByte {
}
}
@Override
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
int sl = sp + len;
@ -451,8 +472,13 @@ public class DoubleByte {
b2cSB_UNMAPPABLE = new char[0x100];
Arrays.fill(b2cSB_UNMAPPABLE, UNMAPPABLE_DECODING);
}
public Decoder_DBCSONLY(Charset cs, char[][] b2c, char[] b2cSB, int b2Min, int b2Max,
boolean isASCIICompatible) {
super(cs, 0.5f, 1.0f, b2c, b2cSB_UNMAPPABLE, b2Min, b2Max, isASCIICompatible);
}
public Decoder_DBCSONLY(Charset cs, char[][] b2c, char[] b2cSB, int b2Min, int b2Max) {
super(cs, 0.5f, 1.0f, b2c, b2cSB_UNMAPPABLE, b2Min, b2Max);
super(cs, 0.5f, 1.0f, b2c, b2cSB_UNMAPPABLE, b2Min, b2Max, false);
}
}
@ -464,8 +490,9 @@ public class DoubleByte {
private final int SS3 = 0x8F;
public Decoder_EUC_SIM(Charset cs,
char[][] b2c, char[] b2cSB, int b2Min, int b2Max) {
super(cs, b2c, b2cSB, b2Min, b2Max);
char[][] b2c, char[] b2cSB, int b2Min, int b2Max,
boolean isASCIICompatible) {
super(cs, b2c, b2cSB, b2Min, b2Max, isASCIICompatible);
}
// No support provided for G2/G3 for SimpleEUC
@ -481,6 +508,7 @@ public class DoubleByte {
return CoderResult.unmappableForLength(2);
}
@Override
public int decode(byte[] src, int sp, int len, char[] dst) {
int dp = 0;
int sl = sp + len;
@ -515,17 +543,25 @@ public class DoubleByte {
private final char[] c2b;
private final char[] c2bIndex;
protected Surrogate.Parser sgp;
final boolean isASCIICompatible;
public Encoder(Charset cs, char[] c2b, char[] c2bIndex) {
this(cs, c2b, c2bIndex, false);
}
public Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible) {
super(cs, 2.0f, 2.0f);
this.c2b = c2b;
this.c2bIndex = c2bIndex;
this.isASCIICompatible = isASCIICompatible;
}
public Encoder(Charset cs, float avg, float max, byte[] repl, char[] c2b, char[] c2bIndex) {
public Encoder(Charset cs, float avg, float max, byte[] repl, char[] c2b, char[] c2bIndex,
boolean isASCIICompatible) {
super(cs, avg, max, repl);
this.c2b = c2b;
this.c2bIndex = c2bIndex;
this.isASCIICompatible = isASCIICompatible;
}
public boolean canEncode(char c) {
@ -624,6 +660,7 @@ public class DoubleByte {
repl = newReplacement;
}
@Override
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
@ -647,11 +684,69 @@ public class DoubleByte {
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
@Override
public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
while (sp < sl) {
char c = (char)(src[sp++] & 0xff);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
// no surrogate pair in latin1 string
dst[dp++] = repl[0];
if (repl.length > 1) {
dst[dp++] = repl[1];
}
continue;
} //else
if (bb > MAX_SINGLEBYTE) { // DoubleByte
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
@Override
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(src, sp))) {
sp++;
}
dst[dp++] = repl[0];
if (repl.length > 1) {
dst[dp++] = repl[1];
}
continue;
} //else
if (bb > MAX_SINGLEBYTE) { // DoubleByte
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
public int encodeChar(char ch) {
return c2b[c2bIndex[ch >> 8] + (ch & 0xff)];
}
@ -741,9 +836,11 @@ public class DoubleByte {
}
public static class Encoder_DBCSONLY extends Encoder {
public Encoder_DBCSONLY(Charset cs, byte[] repl,
char[] c2b, char[] c2bIndex) {
super(cs, 2.0f, 2.0f, repl, c2b, c2bIndex);
char[] c2b, char[] c2bIndex,
boolean isASCIICompatible) {
super(cs, 2.0f, 2.0f, repl, c2b, c2bIndex, isASCIICompatible);
}
public int encodeChar(char ch) {
@ -754,8 +851,6 @@ public class DoubleByte {
}
}
public static class Encoder_EBCDIC extends Encoder {
static final int SBCS = 0;
static final int DBCS = 1;
@ -764,8 +859,9 @@ public class DoubleByte {
protected int currentState = SBCS;
public Encoder_EBCDIC(Charset cs, char[] c2b, char[] c2bIndex) {
super(cs, 4.0f, 5.0f, new byte[] {(byte)0x6f}, c2b, c2bIndex);
public Encoder_EBCDIC(Charset cs, char[] c2b, char[] c2bIndex,
boolean isASCIICompatible) {
super(cs, 4.0f, 5.0f, new byte[] {(byte)0x6f}, c2b, c2bIndex, isASCIICompatible);
}
protected void implReset() {
@ -878,6 +974,7 @@ public class DoubleByte {
}
}
@Override
public int encode(char[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
@ -917,12 +1014,88 @@ public class DoubleByte {
}
return dp;
}
@Override
public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
while (sp < sl) {
char c = (char)(src[sp++] & 0xff);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
// no surrogate pair in latin1 string
dst[dp++] = repl[0];
if (repl.length > 1)
dst[dp++] = repl[1];
continue;
} //else
if (bb > MAX_SINGLEBYTE) { // DoubleByte
if (currentState == SBCS) {
currentState = DBCS;
dst[dp++] = SO;
}
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
if (currentState == DBCS) {
currentState = SBCS;
dst[dp++] = SI;
}
dst[dp++] = (byte)bb;
}
}
if (currentState == DBCS) {
currentState = SBCS;
dst[dp++] = SI;
}
return dp;
}
@Override
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(src, sp))) {
sp++;
}
dst[dp++] = repl[0];
if (repl.length > 1)
dst[dp++] = repl[1];
continue;
} //else
if (bb > MAX_SINGLEBYTE) { // DoubleByte
if (currentState == SBCS) {
currentState = DBCS;
dst[dp++] = SO;
}
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
if (currentState == DBCS) {
currentState = SBCS;
dst[dp++] = SI;
}
dst[dp++] = (byte)bb;
}
}
if (currentState == DBCS) {
currentState = SBCS;
dst[dp++] = SI;
}
return dp;
}
}
// EUC_SIMPLE
public static class Encoder_EUC_SIM extends Encoder {
public Encoder_EUC_SIM(Charset cs, char[] c2b, char[] c2bIndex) {
super(cs, c2b, c2bIndex);
public Encoder_EUC_SIM(Charset cs, char[] c2b, char[] c2bIndex,
boolean isASCIICompatible) {
super(cs, c2b, c2bIndex, isASCIICompatible);
}
}

View File

@ -53,7 +53,7 @@ public class HKSCS {
// super(cs, 0.5f, 1.0f);
// need to extends DoubleByte.Decoder so the
// sun.io can use it. this implementation
super(cs, 0.5f, 1.0f, null, null, 0, 0);
super(cs, 0.5f, 1.0f, null, null, 0, 0, true);
this.big5Dec = big5Dec;
this.b2cBmp = b2cBmp;
this.b2cSupp = b2cSupp;
@ -239,7 +239,7 @@ public class HKSCS {
char[][] c2bBmp,
char[][] c2bSupp)
{
super(cs, null, null);
super(cs, null, null, true);
this.big5Enc = big5Enc;
this.c2bBmp = c2bBmp;
this.c2bSupp = c2bSupp;
@ -389,6 +389,33 @@ public class HKSCS {
return dp;
}
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + len;
int dl = dst.length;
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int bb = encodeChar(c);
if (bb == UNMAPPABLE_ENCODING) {
if (!Character.isHighSurrogate(c) || sp == sl ||
!Character.isLowSurrogate(StringUTF16.getChar(src,sp)) ||
(bb = encodeSupp(Character.toCodePoint(c, StringUTF16.getChar(src, sp++))))
== UNMAPPABLE_ENCODING) {
dst[dp++] = repl[0];
if (repl.length > 1)
dst[dp++] = repl[1];
continue;
}
}
if (bb > MAX_SINGLEBYTE) { // DoubleByte
dst[dp++] = (byte)(bb >> 8);
dst[dp++] = (byte)bb;
} else { // SingleByte
dst[dp++] = (byte)bb;
}
}
return dp;
}
static char[] C2B_UNMAPPABLE = new char[0x100];
static {

View File

@ -132,6 +132,10 @@ class ISO_8859_1
dst[dp++] = (char)(src[sp++] & 0xff);
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
@ -297,5 +301,9 @@ class ISO_8859_1
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -49,10 +49,18 @@ public class SingleByte
public static final class Decoder extends CharsetDecoder
implements ArrayDecoder {
private final char[] b2c;
private final boolean isASCIICompatible;
public Decoder(Charset cs, char[] b2c) {
super(cs, 1.0f, 1.0f);
this.b2c = b2c;
this.isASCIICompatible = false;
}
public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible) {
super(cs, 1.0f, 1.0f);
this.b2c = b2c;
this.isASCIICompatible = isASCIICompatible;
}
private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
@ -116,6 +124,7 @@ public class SingleByte
repl = newReplacement.charAt(0);
}
@Override
public int decode(byte[] src, int sp, int len, char[] dst) {
if (len > dst.length)
len = dst.length;
@ -129,6 +138,11 @@ public class SingleByte
}
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
}
public static final class Encoder extends CharsetEncoder
@ -136,11 +150,13 @@ public class SingleByte
private Surrogate.Parser sgp;
private final char[] c2b;
private final char[] c2bIndex;
private final boolean isASCIICompatible;
public Encoder(Charset cs, char[] c2b, char[] c2bIndex) {
public Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible) {
super(cs, 1.0f, 1.0f);
this.c2b = c2b;
this.c2bIndex = c2bIndex;
this.isASCIICompatible = isASCIICompatible;
}
public boolean canEncode(char c) {
@ -252,6 +268,51 @@ public class SingleByte
}
return dp;
}
@Override
public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = (char)(src[sp++] & 0xff);
int b = encode(c);
if (b == UNMAPPABLE_ENCODING) {
dst[dp++] = repl;
} else {
dst[dp++] = (byte)b;
}
}
return dp;
}
@Override
public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) {
int dp = 0;
int sl = sp + Math.min(len, dst.length);
while (sp < sl) {
char c = StringUTF16.getChar(src, sp++);
int b = encode(c);
if (b != UNMAPPABLE_ENCODING) {
dst[dp++] = (byte)b;
continue;
}
if (Character.isHighSurrogate(c) && sp < sl &&
Character.isLowSurrogate(StringUTF16.getChar(src, sp))) {
if (len > dst.length) {
sl++;
len--;
}
sp++;
}
dst[dp++] = repl;
}
return dp;
}
@Override
public boolean isASCIICompatible() {
return isASCIICompatible;
}
}
// init the c2b and c2bIndex tables from b2c.

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.cs;
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
import static sun.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE;
class StringUTF16 {
public static char getChar(byte[] val, int index) {
return unsafe.getChar(val,
ARRAY_BYTE_BASE_OFFSET + ARRAY_BYTE_INDEX_SCALE * index * 2L);
}
private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
}

View File

@ -146,6 +146,10 @@ public class US_ASCII
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static class Encoder extends CharsetEncoder
@ -259,6 +263,10 @@ public class US_ASCII
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -549,6 +549,10 @@ class UTF_8 extends Unicode
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
private static final class Encoder extends CharsetEncoder
@ -742,5 +746,9 @@ class UTF_8 extends Unicode
}
return dp;
}
public boolean isASCIICompatible() {
return true;
}
}
}

View File

@ -31,3 +31,14 @@ Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
return JVM_InternString(env, this);
}
JNIEXPORT jboolean JNICALL
Java_java_lang_StringUTF16_isBigEndian(JNIEnv *env, jclass cls)
{
unsigned int endianTest = 0xff000000;
if (((char*)(&endianTest))[0] != 0) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}

View File

@ -51,12 +51,12 @@ public class Big5_Solaris extends Charset implements HistoricallyNamedCharset
public CharsetDecoder newDecoder() {
initb2c();
return new DoubleByte.Decoder(this, b2c, b2cSB, 0x40, 0xfe);
return new DoubleByte.Decoder(this, b2c, b2cSB, 0x40, 0xfe, true);
}
public CharsetEncoder newEncoder() {
initc2b();
return new DoubleByte.Encoder(this, c2b, c2bIndex);
return new DoubleByte.Encoder(this, c2b, c2bIndex, true);
}
static char[][] b2c;

View File

@ -62,7 +62,7 @@ public class IBM834 extends Charset
protected static class Encoder extends DoubleByte.Encoder_DBCSONLY {
public Encoder(Charset cs) {
super(cs, new byte[] {(byte)0xfe, (byte)0xfe},
IBM933.c2b, IBM933.c2bIndex);
IBM933.c2b, IBM933.c2bIndex, false);
}
public int encodeChar(char ch) {

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
@test
@bug 8054307
@summary test chars() and codePoints()
*/
import java.util.Arrays;
import java.util.Random;
public class Chars {
public static void main(String[] args) {
Random r = new Random();
for (int i = 0; i < 10; i++) {
int n = 100 + r.nextInt(100);
char[] cc = new char[n];
int[] ccExp = new int[n];
int[] cpExp = new int[n];
// latin1
for (int j = 0; j < n; j++) {
cc[j] = (char)(ccExp[j] = cpExp[j] = r.nextInt(0x80));
}
testChars(cc, ccExp);
testCPs(cc, cpExp);
// bmp without surrogates
for (int j = 0; j < n; j++) {
cc[j] = (char)(ccExp[j] = cpExp[j] = r.nextInt(0x8000));
}
testChars(cc, ccExp);
testCPs(cc, cpExp);
// bmp with surrogates
int k = 0;
for (int j = 0; j < n; j++) {
if (j % 9 == 5 && j + 1 < n) {
int cp = 0x10000 + r.nextInt(2000);
cpExp[k++] = cp;
Character.toChars(cp, cc, j);
ccExp[j] = cc[j];
ccExp[j + 1] = cc[j + 1];
j++;
} else {
cc[j] = (char)(ccExp[j] = cpExp[k++] = r.nextInt(0x8000));
}
}
cpExp = Arrays.copyOf(cpExp, k);
testChars(cc, ccExp);
testCPs(cc, cpExp);
}
}
static void testChars(char[] cc, int[] expected) {
String str = new String(cc);
if (!Arrays.equals(expected, str.chars().toArray())) {
throw new RuntimeException("chars/codePoints() failed!");
}
}
static void testCPs(char[] cc, int[] expected) {
String str = new String(cc);
if (!Arrays.equals(expected, str.codePoints().toArray())) {
throw new RuntimeException("chars/codePoints() failed!");
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.stream.IntStream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.charAt.
* @run testng/othervm -XX:+CompactStrings CharAt
* @run testng/othervm -XX:-CompactStrings CharAt
*/
public class CharAt extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_L1, new char[] { 'A' } },
new Object[] { STRING_L2, new char[] { 'A', 'B' } },
new Object[] { STRING_L4, new char[] { 'A', 'B', 'C', 'D' } },
new Object[] { STRING_LLONG,
new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' } },
new Object[] { STRING_U1, new char[] { '\uFF21' } },
new Object[] { STRING_U2, new char[] { '\uFF21', '\uFF22' } },
new Object[] { STRING_M12, new char[] { '\uFF21', 'A' } },
new Object[] { STRING_M11, new char[] { 'A', '\uFF21' } }, };
}
@Test(dataProvider = "provider")
public void testCharAt(String str, char[] expected) {
map.get(str)
.forEach(
(source, data) -> {
IntStream
.range(0, str.length())
.forEach(
i -> assertEquals(
str.charAt(i),
expected[i],
String.format(
"testing String(%s).charAt(%d), source : %s, ",
escapeNonASCIIs(data),
i, source)));
});
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.stream.IntStream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.codePointAt.
* @run testng/othervm -XX:+CompactStrings CodePointAt
* @run testng/othervm -XX:-CompactStrings CodePointAt
*/
public class CodePointAt extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_L1, new int[] { 'A' } },
new Object[] { STRING_L2, new int[] { 'A', 'B' } },
new Object[] { STRING_L4, new int[] { 'A', 'B', 'C', 'D' } },
new Object[] { STRING_LLONG,
new int[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' } },
new Object[] { STRING_U1, new int[] { '\uFF21' } },
new Object[] { STRING_U2, new int[] { '\uFF21', '\uFF22' } },
new Object[] { STRING_M12, new int[] { '\uFF21', 'A' } },
new Object[] { STRING_M11, new int[] { 'A', '\uFF21' } },
new Object[] {
STRING_SUPPLEMENTARY,
new int[] { Character.toCodePoint('\uD801', '\uDC00'),
'\uDC00',
Character.toCodePoint('\uD801', '\uDC01'),
'\uDC01', '\uFF21', 'A' }, } };
}
@Test(dataProvider = "provider")
public void testCodePointAt(String str, int[] expected) {
map.get(str)
.forEach(
(source, data) -> {
IntStream
.range(0, str.length())
.forEach(
i -> assertEquals(
str.codePointAt(i),
expected[i],
String.format(
"testing String(%s).codePointAt(%d), source : %s, ",
escapeNonASCIIs(data),
i, source)));
});
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.stream.IntStream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.codePointBefore.
* @run testng/othervm -XX:+CompactStrings CodePointBefore
* @run testng/othervm -XX:-CompactStrings CodePointBefore
*/
public class CodePointBefore extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_L1, new int[] { 'A' } },
new Object[] { STRING_L2, new int[] { 'A', 'B' } },
new Object[] { STRING_L4, new int[] { 'A', 'B', 'C', 'D' } },
new Object[] { STRING_LLONG,
new int[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' } },
new Object[] { STRING_U1, new int[] { '\uFF21' } },
new Object[] { STRING_U2, new int[] { '\uFF21', '\uFF22' } },
new Object[] { STRING_M12, new int[] { '\uFF21', 'A' } },
new Object[] { STRING_M11, new int[] { 'A', '\uFF21' } },
new Object[] {
STRING_SUPPLEMENTARY,
new int[] { '\uD801', Character.toCodePoint('\uD801', '\uDC00'),
'\uD801', Character.toCodePoint('\uD801', '\uDC01'),
'\uFF21', 'A' }, } };
}
@Test(dataProvider = "provider")
public void testCodePointBefore(String str, int[] expected) {
map.get(str)
.forEach(
(source, data) -> {
IntStream
.range(0, str.length())
.forEach(
i -> assertEquals(
str.codePointBefore(i + 1),
expected[i],
String.format(
"testing String(%s).codePointBefore(%d), source : %s, ",
escapeNonASCIIs(data),
i + 1, source)));
});
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.codePointCount.
* @run testng/othervm -XX:+CompactStrings CodePointCount
* @run testng/othervm -XX:-CompactStrings CodePointCount
*/
public class CodePointCount extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] { new Object[] { STRING_EMPTY, 0, 0, 0 },
new Object[] { STRING_L1, 0, 1, 1 },
new Object[] { STRING_L1, 1, 1, 0 },
new Object[] { STRING_L2, 0, 2, 2 },
new Object[] { STRING_L2, 0, 1, 1 },
new Object[] { STRING_L2, 1, 2, 1 },
new Object[] { STRING_L4, 0, 4, 4 },
new Object[] { STRING_L4, 0, 1, 1 },
new Object[] { STRING_L4, 2, 4, 2 },
new Object[] { STRING_LLONG, 0, 8, 8 },
new Object[] { STRING_LLONG, 0, 5, 5 },
new Object[] { STRING_LLONG, 4, 8, 4 },
new Object[] { STRING_LLONG, 0, 7, 7 },
new Object[] { STRING_U1, 0, 1, 1 },
new Object[] { STRING_U2, 0, 2, 2 },
new Object[] { STRING_U2, 0, 1, 1 },
new Object[] { STRING_U2, 1, 2, 1 },
new Object[] { STRING_M12, 0, 2, 2 },
new Object[] { STRING_M12, 0, 1, 1 },
new Object[] { STRING_M12, 1, 2, 1 },
new Object[] { STRING_M11, 0, 2, 2 },
new Object[] { STRING_M11, 0, 1, 1 },
new Object[] { STRING_M11, 1, 2, 1 },
new Object[] { STRING_SUPPLEMENTARY, 0, 1, 1 },
new Object[] { STRING_SUPPLEMENTARY, 0, 2, 1 },
new Object[] { STRING_SUPPLEMENTARY, 0, 3, 2 },
new Object[] { STRING_SUPPLEMENTARY, 0, 5, 3 },
new Object[] { STRING_SUPPLEMENTARY, 0, 6, 4 },
new Object[] { STRING_SUPPLEMENTARY, 1, 4, 2 },
new Object[] { STRING_SUPPLEMENTARY, 1, 6, 4 },
new Object[] { STRING_SUPPLEMENTARY, 2, 4, 1 },};
}
@Test(dataProvider = "provider")
public void testCodePointCount(String str, int beginIndex, int endIndex,
int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.codePointCount(beginIndex, endIndex),
expected,
String.format(
"testing String(%s).codePointCount(%d, %d), source : %s, ",
escapeNonASCIIs(data), beginIndex,
endIndex, source));
});
}
}

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.BeforeClass;
/*
* Base class of tests for Compact String.
*
*/
public class CompactString {
final Map<String, Map<String, String>> map = new HashMap<>();
enum StringSources {
EMPTY(STRING_EMPTY, BYTE_ARRAY_EMTPY, CHAR_ARRAY_EMPTY,
POINT_ARRAY_EMTPY), LDUPLICATE(STRING_LDUPLICATE,
BYTE_ARRAY_LDUPLICATE, CHAR_ARRAY_LDUPLICATE,
POINT_ARRAY_LDUPLICATE), LLONG(STRING_LLONG, BYTE_ARRAY_LLONG,
CHAR_ARRAY_LLONG, POINT_ARRAY_LLONG), L1(STRING_L1,
BYTE_ARRAY_L1, CHAR_ARRAY_L1, POINT_ARRAY_L1), L2(STRING_L2,
BYTE_ARRAY_L2, CHAR_ARRAY_L2, POINT_ARRAY_L2), L4(STRING_L4,
BYTE_ARRAY_L4, CHAR_ARRAY_L4, POINT_ARRAY_L4), UDUPLICATE(
STRING_UDUPLICATE, BYTE_ARRAY_UDUPLICATE,
CHAR_ARRAY_UDUPLICATE, POINT_ARRAY_UDUPLICATE), U1(STRING_U1,
BYTE_ARRAY_U1, CHAR_ARRAY_U1, POINT_ARRAY_U1), U2(STRING_U2,
BYTE_ARRAY_U2, CHAR_ARRAY_U2, POINT_ARRAY_U2), MDUPLICATE1(
STRING_MDUPLICATE1, BYTE_ARRAY_MDUPLICATE1,
CHAR_ARRAY_MDUPLICATE1, POINT_ARRAY_MDUPLICATE1), MDUPLICATE2(
STRING_MDUPLICATE2, BYTE_ARRAY_MDUPLICATE2,
CHAR_ARRAY_MDUPLICATE2, POINT_ARRAY_MDUPLICATE2), MLONG1(
STRING_MLONG1, BYTE_ARRAY_MLONG1, CHAR_ARRAY_MLONG1,
POINT_ARRAY_MLONG1), MLONG2(STRING_MLONG2, BYTE_ARRAY_MLONG2,
CHAR_ARRAY_MLONG2, POINT_ARRAY_MLONG2), M11(STRING_M11,
BYTE_ARRAY_M11, CHAR_ARRAY_M11, POINT_ARRAY_M11), M12(
STRING_M12, BYTE_ARRAY_M12, CHAR_ARRAY_M12, POINT_ARRAY_M12), SUPPLEMENTARY(
STRING_SUPPLEMENTARY, BYTE_ARRAY_SUPPLEMENTARY,
CHAR_ARRAY_SUPPLEMENTARY, POINT_ARRAY_SUPPLEMENTARY), SUPPLEMENTARY_LOWERCASE(
STRING_SUPPLEMENTARY_LOWERCASE,
BYTE_ARRAY_SUPPLEMENTARY_LOWERCASE,
CHAR_ARRAY_SUPPLEMENTARY_LOWERCASE,
POINT_ARRAY_SUPPLEMENTARY_LOWERCASE);
private StringSources(String s, byte[] b, char[] c, int[] i) {
str = s;
ba = b;
ca = c;
ia = i;
}
String getString() {
return str;
}
byte[] getByteArray() {
return ba;
}
char[] getCharArray() {
return ca;
}
int[] getIntArray() {
return ia;
}
private final String str;
private final byte[] ba;
private final char[] ca;
private final int[] ia;
}
protected static final String DEFAULT_CHARSET_NAME = "UTF-8";
protected static final Charset DEFAULT_CHARSET = Charset
.forName(DEFAULT_CHARSET_NAME);
protected static final String STRING_EMPTY = "";
protected static final byte[] BYTE_ARRAY_EMTPY = new byte[0];
protected static final char[] CHAR_ARRAY_EMPTY = new char[0];
protected static final int[] POINT_ARRAY_EMTPY = new int[0];
protected static final String STRING_LDUPLICATE = "ABABABABAB";
protected static final byte[] BYTE_ARRAY_LDUPLICATE = new byte[] { 'A', 'B',
'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B' };
protected static final char[] CHAR_ARRAY_LDUPLICATE = new char[] { 'A', 'B',
'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B' };
protected static final int[] POINT_ARRAY_LDUPLICATE = new int[] { 'A', 'B',
'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B' };
protected static final String STRING_LLONG = "ABCDEFGH";
protected static final byte[] BYTE_ARRAY_LLONG = new byte[] { 'A', 'B', 'C',
'D', 'E', 'F', 'G', 'H' };
protected static final char[] CHAR_ARRAY_LLONG = new char[] { 'A', 'B', 'C',
'D', 'E', 'F', 'G', 'H' };
protected static final int[] POINT_ARRAY_LLONG = new int[] { 'A', 'B', 'C',
'D', 'E', 'F', 'G', 'H' };
protected static final String STRING_L1 = "A";
protected static final byte[] BYTE_ARRAY_L1 = new byte[] { 'A' };
protected static final char[] CHAR_ARRAY_L1 = new char[] { 'A' };
protected static final int[] POINT_ARRAY_L1 = new int[] { 'A' };
protected static final String STRING_L2 = "AB";
protected static final byte[] BYTE_ARRAY_L2 = new byte[] { 'A', 'B' };
protected static final char[] CHAR_ARRAY_L2 = new char[] { 'A', 'B' };
protected static final int[] POINT_ARRAY_L2 = new int[] { 'A', 'B' };
protected static final String STRING_L4 = "ABCD";
protected static final byte[] BYTE_ARRAY_L4 = new byte[] { 'A', 'B', 'C', 'D' };
protected static final char[] CHAR_ARRAY_L4 = new char[] { 'A', 'B', 'C', 'D' };
protected static final int[] POINT_ARRAY_L4 = new int[] { 'A', 'B', 'C', 'D' };
/*
* Because right now ASCII is the default encoding parameter for source code
* in JDK build environment, so we escape them. same as below.
*/
protected static final String STRING_UDUPLICATE = "\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22";
protected static final byte[] BYTE_ARRAY_UDUPLICATE = getBytes(STRING_UDUPLICATE);
protected static final char[] CHAR_ARRAY_UDUPLICATE = new char[] { '\uFF21',
'\uFF22', '\uFF21', '\uFF22', '\uFF21', '\uFF22', '\uFF21',
'\uFF22', '\uFF21', '\uFF22' };
protected static final int[] POINT_ARRAY_UDUPLICATE = new int[] { '\uFF21',
'\uFF22', '\uFF21', '\uFF22', '\uFF21', '\uFF22', '\uFF21',
'\uFF22', '\uFF21', '\uFF22' };
protected static final String STRING_U1 = "\uFF21";
protected static final byte[] BYTE_ARRAY_U1 = getBytes(STRING_U1);
protected static final char[] CHAR_ARRAY_U1 = new char[] { '\uFF21' };
protected static final int[] POINT_ARRAY_U1 = new int[] { '\uFF21' };
protected static final String STRING_U2 = "\uFF21\uFF22";
protected static final byte[] BYTE_ARRAY_U2 = getBytes(STRING_U2);
protected static final char[] CHAR_ARRAY_U2 = new char[] { '\uFF21', '\uFF22' };
protected static final int[] POINT_ARRAY_U2 = new int[] { '\uFF21', '\uFF22' };
protected static final String STRING_MDUPLICATE1 = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
protected static final byte[] BYTE_ARRAY_MDUPLICATE1 = getBytes(STRING_MDUPLICATE1);
protected static final char[] CHAR_ARRAY_MDUPLICATE1 = new char[] { '\uFF21',
'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A' };
protected static final int[] POINT_ARRAY_MDUPLICATE1 = new int[] { '\uFF21',
'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A' };
protected static final String STRING_MDUPLICATE2 = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
protected static final byte[] BYTE_ARRAY_MDUPLICATE2 = getBytes(STRING_MDUPLICATE2);
protected static final char[] CHAR_ARRAY_MDUPLICATE2 = new char[] { 'A',
'\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A',
'\uFF21' };
protected static final int[] POINT_ARRAY_MDUPLICATE2 = new int[] { 'A',
'\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A', '\uFF21', 'A',
'\uFF21' };
protected static final String STRING_MLONG1 = "A\uFF21B\uFF22C\uFF23D\uFF24E\uFF25F\uFF26G\uFF27H\uFF28";
protected static final byte[] BYTE_ARRAY_MLONG1 = getBytes(STRING_MLONG1);
protected static final char[] CHAR_ARRAY_MLONG1 = new char[] { 'A', '\uFF21',
'B', '\uFF22', 'C', '\uFF23', 'D', '\uFF24', 'E', '\uFF25', 'F',
'\uFF26', 'G', '\uFF27', 'H', '\uFF28' };
protected static final int[] POINT_ARRAY_MLONG1 = new int[] { 'A', '\uFF21',
'B', '\uFF22', 'C', '\uFF23', 'D', '\uFF24', 'E', '\uFF25', 'F',
'\uFF26', 'G', '\uFF27', 'H', '\uFF28' };
protected static final String STRING_MLONG2 = "\uFF21A\uFF22B\uFF23C\uFF24D\uFF25E\uFF26F\uFF27G\uFF28H";
protected static final byte[] BYTE_ARRAY_MLONG2 = getBytes(STRING_MLONG2);
protected static final char[] CHAR_ARRAY_MLONG2 = new char[] { '\uFF21', 'A',
'\uFF22', 'B', '\uFF23', 'C', '\uFF24', 'D', '\uFF25', 'E',
'\uFF26', 'F', '\uFF27', 'G', '\uFF28', 'H' };
protected static final int[] POINT_ARRAY_MLONG2 = new int[] { '\uFF21', 'A',
'\uFF22', 'B', '\uFF23', 'C', '\uFF24', 'D', '\uFF25', 'E',
'\uFF26', 'F', '\uFF27', 'G', '\uFF28', 'H' };
protected static final String STRING_M11 = "A\uFF21";
protected static final byte[] BYTE_ARRAY_M11 = getBytes(STRING_M11);
protected static final char[] CHAR_ARRAY_M11 = new char[] { 'A', '\uFF21' };
protected static final int[] POINT_ARRAY_M11 = new int[] { 'A', '\uFF21' };
protected static final String STRING_M12 = "\uFF21A";
protected static final byte[] BYTE_ARRAY_M12 = getBytes(STRING_M12);
protected static final char[] CHAR_ARRAY_M12 = new char[] { '\uFF21', 'A' };
protected static final int[] POINT_ARRAY_M12 = new int[] { '\uFF21', 'A' };
protected static final String STRING_SUPPLEMENTARY = "\uD801\uDC00\uD801\uDC01\uFF21A";
protected static final byte[] BYTE_ARRAY_SUPPLEMENTARY = getBytes(STRING_SUPPLEMENTARY);
protected static final char[] CHAR_ARRAY_SUPPLEMENTARY = new char[] {
'\uD801', '\uDC00', '\uD801', '\uDC01', '\uFF21', 'A' };
protected static final int[] POINT_ARRAY_SUPPLEMENTARY = new int[] {
'\uD801', '\uDC00', '\uD801', '\uDC01', '\uFF21', 'A' };
protected static final String STRING_SUPPLEMENTARY_LOWERCASE = "\uD801\uDC28\uD801\uDC29\uFF41a";
protected static final byte[] BYTE_ARRAY_SUPPLEMENTARY_LOWERCASE = getBytes(STRING_SUPPLEMENTARY_LOWERCASE);
protected static final char[] CHAR_ARRAY_SUPPLEMENTARY_LOWERCASE = new char[] {
'\uD801', '\uDC28', '\uD801', '\uDC29', '\uFF41', 'a' };
protected static final int[] POINT_ARRAY_SUPPLEMENTARY_LOWERCASE = new int[] {
'\uD801', '\uDC28', '\uD801', '\uDC29', '\uFF41', 'a' };
protected static final String SRC_BYTE_ARRAY_WITH_CHARSETNAME = "source from byte array with charset name";
protected static final String SRC_BYTE_ARRAY_WITH_CHARSET = "source from byte array with charset";
protected static final String SRC_CHAR_ARRAY = "source from char array";
protected static final String SRC_POINT_ARRAY = "source from code point array";
protected static final String SRC_STRING = "source from String";
protected static final String SRC_STRINGBUFFER = "source from StringBuffer";
protected static final String SRC_STRINGBUILDER = "source from StringBuilder";
protected static final String SRC_COPYVALUEOF = "source from copyValueOf from char array";
protected static final String SRC_VALUEOF = "source from valueOf from char array";
static {
System.out
.println(String
.format("====== The platform's default charset is \"%s\", we're using \"%s\" for testing.",
Charset.defaultCharset().name(),
DEFAULT_CHARSET_NAME));
}
private static byte[] getBytes(String str) {
byte[] res = null;
try {
res = str.getBytes(DEFAULT_CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException("caught UnsupportedEncodingException!!!", e);
}
return res;
}
private void setUpOneString(String content, byte[] ba, char[] ca, int[] cpa)
throws UnsupportedEncodingException {
final Map<String, String> m = new HashMap<>();
m.put(SRC_BYTE_ARRAY_WITH_CHARSETNAME, new String(ba,
DEFAULT_CHARSET_NAME));
m.put(SRC_BYTE_ARRAY_WITH_CHARSET, new String(ba, DEFAULT_CHARSET));
m.put(SRC_CHAR_ARRAY, new String(ca));
m.put(SRC_POINT_ARRAY, new String(cpa, 0, cpa.length));
m.put(SRC_STRING, new String(content));
m.put(SRC_STRINGBUFFER, new String(new StringBuffer(content)));
m.put(SRC_STRINGBUILDER, new String(new StringBuilder(content)));
m.put(SRC_COPYVALUEOF, String.copyValueOf(ca));
m.put(SRC_VALUEOF, String.valueOf(ca));
map.put(content, m);
}
/*
* Set up the test data, use 9 ways to construct one String.
*
* @throws UnsupportedEncodingException
* If the named charset is not supported in setUpOneString(xxx).
*/
@BeforeClass
public void setUp() throws UnsupportedEncodingException {
for (StringSources src : StringSources.values()) {
setUpOneString(src.getString(), src.getByteArray(),
src.getCharArray(), src.getIntArray());
}
}
/*
* Because right now system default charset in JPRT environment is only
* guaranteed to support ASCII characters in log, so we escape them.
*/
protected String escapeNonASCIIs(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c > 0x7F) {
sb.append("\\u").append(Integer.toHexString((int) c));
} else {
sb.append(c);
}
}
return sb.toString();
}
/*
* Because right now system default charset in JPRT environment is only
* guaranteed to support ASCII characters in log, so we escape them.
*/
protected String escapeNonASCII(char c) {
StringBuilder sb = new StringBuilder();
if (c > 0x7F) {
sb.append("\\u").append(Integer.toHexString((int) c));
} else {
sb.append(c);
}
return sb.toString();
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.compareTo.
* @run testng/othervm -XX:+CompactStrings CompareTo
* @run testng/othervm -XX:-CompactStrings CompareTo
*/
public class CompareTo extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", -1 },
new Object[] { STRING_EMPTY, "\uFF21", -1 },
new Object[] { STRING_L1, "AB", -1 },
new Object[] { STRING_L1, "A", 0 },
new Object[] { STRING_L1, "a", -32 },
new Object[] { STRING_L1, "\uFF21", -65248 },
new Object[] { STRING_L2, "AB", 0 },
new Object[] { STRING_L2, "Ab", -32 },
new Object[] { STRING_L2, "AA", 1 },
new Object[] { STRING_L2, "\uFF21", -65248 },
new Object[] { STRING_L2, "A\uFF21", -65247 },
new Object[] { STRING_L4, "ABC", 1 },
new Object[] { STRING_L4, "AB", 2 },
new Object[] { STRING_L4, "ABcD", -32 },
new Object[] { STRING_L4, "ABCD\uFF21\uFF21", -2 },
new Object[] { STRING_L4, "ABCD\uFF21", -1 },
new Object[] { STRING_LLONG, "ABCDEFG\uFF21", -65241 },
new Object[] { STRING_LLONG, "AB", 6 },
new Object[] { STRING_LLONG, "ABCD", 4 },
new Object[] { STRING_LLONG, "ABCDEFGH\uFF21\uFF21", -2 },
new Object[] { STRING_U1, "\uFF21", 0 },
new Object[] { STRING_U1, "\uFF22", -1 },
new Object[] { STRING_U1, "\uFF21\uFF22", -1 },
new Object[] { STRING_U1, "A", 65248 },
new Object[] { STRING_U2, "\uFF21\uFF22", 0 },
new Object[] { STRING_U2, "\uFF22", -1 },
new Object[] { STRING_U2, "\uFF21\uFF21", 1 },
new Object[] { STRING_U2, "A", 65248 },
new Object[] { STRING_M12, "\uFF21A", 0 },
new Object[] { STRING_M12, "A\uFF21", 65248 },
new Object[] { STRING_M12, "\uFF21\uFF21", -65248 },
new Object[] { STRING_M11, "A\uFF21", 0 },
new Object[] { STRING_M11, "\uFF21A", -65248 },
new Object[] { STRING_M11, "AA", 65248 }, };
}
@Test(dataProvider = "provider")
public void testCompareTo(String str, String anotherString, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.compareTo(anotherString),
expected,
String.format(
"testing String(%s).compareTo(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.compareToIgnoreCase.
* @run testng/othervm -XX:+CompactStrings CompareToIgnoreCase
* @run testng/othervm -XX:-CompactStrings CompareToIgnoreCase
*/
public class CompareToIgnoreCase extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", -1 },
new Object[] { STRING_L1, "a", 0 },
new Object[] { STRING_L1, "A", 0 },
new Object[] { STRING_L1, "\uFF21", -65248 },
new Object[] { STRING_L1, "B", -1 },
new Object[] { STRING_L2, "AB", 0 },
new Object[] { STRING_L2, "aB", 0 },
new Object[] { STRING_L2, "\uFF21", -65248 },
new Object[] { STRING_L2, "A\uFF21", -65247 },
new Object[] { STRING_L4, "ABCD", 0 },
new Object[] { STRING_L4, "abcd", 0 },
new Object[] { STRING_L4, "ABc\uFF21", -65245 },
new Object[] { STRING_LLONG, "ABCDEFGH", 0 },
new Object[] { STRING_LLONG, "abcdefgh", 0 },
new Object[] { STRING_LLONG, "ABCDEFG\uFF21", -65241 },
new Object[] { STRING_LLONG, "abcdefg\uFF21", -65241 },
new Object[] { STRING_U1, "\uFF41", 0 },
new Object[] { STRING_U1,
"\uFF41\uFF42\uFF43\uFF44\uFF45\uFF46\uFF47\uFF48", -7 },
new Object[] { STRING_U1, "A", 65248 },
new Object[] { STRING_U2, "\uFF41", 1 },
new Object[] { STRING_U2, "\uFF41\uFF42", 0 },
new Object[] { STRING_U2,
"\uFF41\uFF42\uFF43\uFF44\uFF45\uFF46\uFF47\uFF48", -6 },
new Object[] { STRING_M12, "\uFF41a", 0 },
new Object[] { STRING_M12, "\uFF41\uFF42", -65249 },
new Object[] { STRING_M11, "a\uFF41", 0 },
new Object[] { STRING_M11, "a\uFF42", -1 }, };
}
@Test(dataProvider = "provider")
public void testCompareToIgnoreCase(String str, String anotherString,
int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.compareToIgnoreCase(anotherString),
expected,
String.format(
"testing String(%s).compareToIgnoreCase(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.concat.
* @run testng/othervm -XX:+CompactStrings Concat
* @run testng/othervm -XX:-CompactStrings Concat
*/
public class Concat extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "ABC", "ABC" },
new Object[] { STRING_EMPTY,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"ABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_EMPTY,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_L1,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"AABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_L1,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"A\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_L2,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"ABABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_L2,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"AB\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_L4,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"ABCDABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_L4,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"ABCD\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_LLONG,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"ABCDEFGHABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_LLONG,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"ABCDEFGH\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_U1,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"\uFF21ABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_U1,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"\uFF21\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_U2,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"\uFF21\uFF22ABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_U2,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"\uFF21\uFF22\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_M12,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"\uFF21AABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_M12,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"\uFF21A\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" },
new Object[] { STRING_M11,
"ABC".concat("\uFF21\uFF22\uFF23").concat("DEF"),
"A\uFF21ABC\uFF21\uFF22\uFF23DEF" },
new Object[] {
STRING_M11,
"\uFF21\uFF22\uFF23".concat("ABC").concat(
"\uFF24\uFF25\uFF26"),
"A\uFF21\uFF21\uFF22\uFF23ABC\uFF24\uFF25\uFF26" }, };
}
@Test(dataProvider = "provider")
public void testConcat(String str, String anotherString, String expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.concat(anotherString),
expected,
String.format(
"testing String(%s).concat(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.contains.
* @run testng/othervm -XX:+CompactStrings Contains
* @run testng/othervm -XX:-CompactStrings Contains
*/
public class Contains extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "", true },
new Object[] { STRING_EMPTY, "A", false },
new Object[] { STRING_EMPTY, "\uFF21", false },
new Object[] { STRING_L1, "", true },
new Object[] { STRING_L1, "A", true },
new Object[] { STRING_L1, "\uFF21", false },
new Object[] { STRING_L2, "", true },
new Object[] { STRING_L2, "A", true },
new Object[] { STRING_L2, "AB", true },
new Object[] { STRING_L2, "B", true },
new Object[] { STRING_L2, "ABC", false },
new Object[] { STRING_L2, "ab", false },
new Object[] { STRING_L4, "ABCD", true },
new Object[] { STRING_L4, "BC", true },
new Object[] { STRING_LLONG, "ABCDEFGH", true },
new Object[] { STRING_LLONG, "BCDEFGH", true },
new Object[] { STRING_LLONG, "EF", true },
new Object[] { STRING_U1, "", true },
new Object[] { STRING_U1, "\uFF21", true },
new Object[] { STRING_U1, "a", false },
new Object[] { STRING_U1, "\uFF21B", false },
new Object[] { STRING_U2, "", true },
new Object[] { STRING_U2, "\uFF21\uFF22", true },
new Object[] { STRING_U2, "a", false },
new Object[] { STRING_U2, "\uFF21B", false },
new Object[] { STRING_M12, "\uFF21A", true },
new Object[] { STRING_M12, "\uFF21", true },
new Object[] { STRING_M12, "A", true },
new Object[] { STRING_M12, "A\uFF21", false },
new Object[] { STRING_M11, "A\uFF21", true },
new Object[] { STRING_M11, "Ab", false }, };
}
@Test(dataProvider = "provider")
public void testContains(String str, String anotherString, boolean expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.contains(anotherString),
expected,
String.format(
"testing String(%s).contains(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.endsWith.
* @run testng/othervm -XX:+CompactStrings EndsWith
* @run testng/othervm -XX:-CompactStrings EndsWith
*/
public class EndsWith extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] { new Object[] { STRING_EMPTY, "", true },
new Object[] { STRING_EMPTY, "A", false },
new Object[] { STRING_L1, "A", true },
new Object[] { STRING_L1, "", true },
new Object[] { STRING_L1, " ", false },
new Object[] { STRING_L2, "AB", true },
new Object[] { STRING_L2, "B", true },
new Object[] { STRING_L2, "", true },
new Object[] { STRING_L2, "A", false },
new Object[] { STRING_L4, "ABCD", true },
new Object[] { STRING_L4, "CD", true },
new Object[] { STRING_L4, "D", true },
new Object[] { STRING_L4, "", true },
new Object[] { STRING_L4, "BC", false },
new Object[] { STRING_LLONG, "ABCDEFGH", true },
new Object[] { STRING_LLONG, "EFGH", true },
new Object[] { STRING_LLONG, "", true },
new Object[] { STRING_LLONG, "CDEF", false },
new Object[] { STRING_LLONG, "\uFF28", false },
new Object[] { STRING_U1, "\uFF21", true },
new Object[] { STRING_U1, "", true },
new Object[] { STRING_U1, "\uFF22", false },
new Object[] { STRING_U1, "B", false },
new Object[] { STRING_U2, "\uFF21\uFF22", true },
new Object[] { STRING_U2, "\uFF22", true },
new Object[] { STRING_U2, "", true },
new Object[] { STRING_U2, "\uFF21", false },
new Object[] { STRING_M12, "\uFF21A", true },
new Object[] { STRING_M12, "A", true },
new Object[] { STRING_M12, "", true },
new Object[] { STRING_M12, "AA", false },
new Object[] { STRING_M11, "A\uFF21", true },
new Object[] { STRING_M11, "\uFF21", true },
new Object[] { STRING_M11, "", true },
new Object[] { STRING_M11, "\uFF21\uFF21", false }, };
}
@Test(dataProvider = "provider")
public void testEndsWith(String str, String suffix, boolean expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.endsWith(suffix),
expected,
String.format(
"testing String(%s).endsWith(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(suffix), source));
});
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.equals.
* @run testng/othervm -XX:+CompactStrings Equals
* @run testng/othervm -XX:-CompactStrings Equals
*/
public class Equals extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "", true },
new Object[] { STRING_EMPTY, "A", false },
new Object[] { STRING_EMPTY, new StringBuffer(""), false },
new Object[] { STRING_L1, "A", true },
new Object[] { STRING_L1, "", false },
new Object[] { STRING_L1, new StringBuffer("A"), false },
new Object[] { STRING_L2, "AB", true },
new Object[] { STRING_L2, "", false },
new Object[] { STRING_L2, new StringBuilder("AB"), false },
new Object[] { STRING_L4, "ABCD", true },
new Object[] { STRING_L4, "abc", false },
new Object[] { STRING_L4, "", false },
new Object[] { STRING_LLONG, "ABCDEFGH", true },
new Object[] { STRING_LLONG, "ABCDEFG", false },
new Object[] { STRING_LLONG, new StringBuilder("ABCDEFGH"),
false },
new Object[] { STRING_U1, "\uFF21", true },
new Object[] { STRING_U1, "", false },
new Object[] { STRING_U2, "\uFF21\uFF22", true },
new Object[] { STRING_U2, "\uFF21", false },
new Object[] { STRING_U2, "", false },
new Object[] { STRING_U2, new StringBuilder("\uFF21\uFF22"),
false },
new Object[] { STRING_M12, "\uFF21A", true },
new Object[] { STRING_M12, "A\uFF21", false },
new Object[] { STRING_M11, "A\uFF21", true },
new Object[] { STRING_M11, new StringBuilder("\uFF21A"), false }, };
}
@Test(dataProvider = "provider")
public void testEquals(String str, Object obj, boolean expected) {
map.get(str).forEach(
(source, data) -> {
assertEquals(data.equals(obj), expected, String.format(
"testing String(%s).equals(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(obj.toString()), source));
});
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.equalsIgnoreCase.
* @run testng/othervm -XX:+CompactStrings EqualsIgnoreCase
* @run testng/othervm -XX:-CompactStrings EqualsIgnoreCase
*/
public class EqualsIgnoreCase extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "", true },
new Object[] { STRING_L1, "a", true },
new Object[] { STRING_L2, "aB", true },
new Object[] { STRING_L4, "AbCd", true },
new Object[] { STRING_LLONG, "aBcDeFgH", true },
new Object[] { STRING_U1, "\uFF41", true },
new Object[] { STRING_U1, "\uFF21", true },
new Object[] { STRING_U2, "\uFF41\uFF42", true },
new Object[] { STRING_U2, "\uFF41\uFF22", true },
new Object[] { STRING_U2, "\uFF21\uFF42", true },
new Object[] { STRING_M12, "\uFF41a", true },
new Object[] { STRING_M12, "\uFF21A", true },
new Object[] { STRING_M11, "a\uFF41", true },
new Object[] { STRING_M11, "A\uFF21", true },
};
}
@Test(dataProvider = "provider")
public void testEqualsIgnoreCase(String str, String anotherString,
boolean expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.equalsIgnoreCase(anotherString),
expected,
String.format(
"testing String(%s).equalsIgnoreCase(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.getChars.
* @run testng/othervm -XX:+CompactStrings GetChars
* @run testng/othervm -XX:-CompactStrings GetChars
*/
public class GetChars extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, 0, STRING_EMPTY.length(),
new char[STRING_EMPTY.length()], 0, CHAR_ARRAY_EMPTY },
new Object[] { STRING_L1, 0, STRING_L1.length(),
new char[STRING_L1.length()], 0, CHAR_ARRAY_L1 },
new Object[] { STRING_L2, 0, STRING_L2.length(),
new char[STRING_L2.length()], 0, CHAR_ARRAY_L2 },
new Object[] { STRING_L4, 0, STRING_L4.length(),
new char[STRING_L4.length()], 0, CHAR_ARRAY_L4 },
new Object[] { STRING_LLONG, 0, STRING_LLONG.length(),
new char[STRING_LLONG.length()], 0, CHAR_ARRAY_LLONG },
new Object[] { STRING_U1, 0, STRING_U1.length(),
new char[STRING_U1.length()], 0, CHAR_ARRAY_U1 },
new Object[] { STRING_U2, 0, STRING_U2.length(),
new char[STRING_U2.length()], 0, CHAR_ARRAY_U2 },
new Object[] { STRING_M12, 0, STRING_M12.length(),
new char[STRING_M12.length()], 0, CHAR_ARRAY_M12 },
new Object[] { STRING_M11, 0, STRING_M11.length(),
new char[STRING_M11.length()], 0, CHAR_ARRAY_M11 },
new Object[] { STRING_UDUPLICATE, 0,
STRING_UDUPLICATE.length(),
new char[STRING_UDUPLICATE.length()], 0,
CHAR_ARRAY_UDUPLICATE },
new Object[] { STRING_MDUPLICATE1, 0,
STRING_MDUPLICATE1.length(),
new char[STRING_MDUPLICATE1.length()], 0,
CHAR_ARRAY_MDUPLICATE1 }, };
}
@Test(dataProvider = "provider")
public void testGetChars(String str, int srcBegin, int srcEnd, char[] dst,
int dstBegin, char[] expected) {
map.get(str)
.forEach(
(source, data) -> {
data.getChars(srcBegin, srcEnd, dst, dstBegin);
assertTrue(
Arrays.equals(dst, expected),
String.format(
"testing String(%s).getChars(%d, %d, %s, %d), source : %s, ",
escapeNonASCIIs(data), srcBegin,
srcEnd, escapeNonASCIIs(Arrays
.toString(dst)), dstBegin,
source));
});
}
}

View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.indexOf.
* @run testng/othervm -XX:+CompactStrings IndexOf
* @run testng/othervm -XX:-CompactStrings IndexOf
*/
public class IndexOf extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, (int) 'A', -1 },
new Object[] { STRING_L1, (int) 'A', 0 },
new Object[] { STRING_L2, (int) 'A', 0 },
new Object[] { STRING_L2, (int) 'B', 1 },
new Object[] { STRING_L4, (int) 'A', 0 },
new Object[] { STRING_L4, (int) 'D', 3 },
new Object[] { STRING_L4, (int) 'E', -1 },
new Object[] { STRING_LLONG, (int) 'A', 0 },
new Object[] { STRING_LLONG, (int) 'H', 7 },
new Object[] { STRING_U1, (int) '\uFF21', 0 },
new Object[] { STRING_U1, (int) 'A', -1 },
new Object[] { STRING_U2, (int) '\uFF21', 0 },
new Object[] { STRING_U2, (int) '\uFF22', 1 },
new Object[] { STRING_M12, (int) '\uFF21', 0 },
new Object[] { STRING_M12, (int) 'A', 1 },
new Object[] { STRING_M11, (int) 'A', 0 },
new Object[] { STRING_M11, (int) '\uFF21', 1 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF21', 0 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF22', 1 },
new Object[] { STRING_SUPPLEMENTARY, 'A', 5 },
new Object[] { STRING_SUPPLEMENTARY, '\uFF21', 4 },
new Object[] { STRING_SUPPLEMENTARY,
Character.toCodePoint('\uD801', '\uDC00'), 0 },
new Object[] { STRING_SUPPLEMENTARY,
Character.toCodePoint('\uD801', '\uDC01'), 2 }, };
}
@Test(dataProvider = "provider")
public void testIndexOf(String str, int ch, int expected) {
map.get(str).forEach(
(source, data) -> {
assertEquals(data.indexOf(ch), expected, String.format(
"testing String(%s).indexOf(%d), source : %s, ",
escapeNonASCIIs(data), ch, source));
});
}
@DataProvider
public Object[][] provider2() {
return new Object[][] {
new Object[] { STRING_EMPTY, (int) 'A', 0, -1 },
new Object[] { STRING_L1, (int) 'A', 0, 0 },
new Object[] { STRING_L1, (int) 'A', 1, -1 },
new Object[] { STRING_L1, (int) 'B', 0, -1 },
new Object[] { STRING_L2, (int) 'A', 0, 0 },
new Object[] { STRING_L2, (int) 'A', 1, -1 },
new Object[] { STRING_L2, (int) 'B', 0, 1 },
new Object[] { STRING_L2, (int) 'B', 1, 1 },
new Object[] { STRING_L4, (int) 'A', 0, 0 },
new Object[] { STRING_L4, (int) 'D', 2, 3 },
new Object[] { STRING_L4, (int) 'B', 2, -1 },
new Object[] { STRING_LLONG, (int) 'A', 0, 0 },
new Object[] { STRING_LLONG, (int) 'H', 5, 7 },
new Object[] { STRING_U1, (int) '\uFF21', 0, 0 },
new Object[] { STRING_U1, (int) 'A', 0, -1 },
new Object[] { STRING_U2, (int) '\uFF21', 0, 0 },
new Object[] { STRING_U2, (int) '\uFF22', 0, 1 },
new Object[] { STRING_M12, (int) '\uFF21', 0, 0 },
new Object[] { STRING_M12, (int) 'A', 1, 1 },
new Object[] { STRING_M11, (int) 'A', 0, 0 },
new Object[] { STRING_M11, (int) '\uFF21', 1, 1 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF21', 1, 2 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF22', 1, 1 }, };
}
@Test(dataProvider = "provider2")
public void testIndexOf(String str, int ch, int fromIndex, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.indexOf(ch, fromIndex),
expected,
String.format(
"testing String(%s).indexOf(%d, %d), source : %s, ",
escapeNonASCIIs(data), ch,
fromIndex, source));
});
}
@DataProvider
public Object[][] provider3() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", -1 },
new Object[] { STRING_L1, "A", 0 },
new Object[] { STRING_L1, "AB", -1 },
new Object[] { STRING_L2, "A", 0 },
new Object[] { STRING_L2, "B", 1 },
new Object[] { STRING_L2, "AB", 0 },
new Object[] { STRING_L2, "AC", -1 },
new Object[] { STRING_L2, "ABC", -1 },
new Object[] { STRING_L4, "ABCD", 0 },
new Object[] { STRING_L4, "D", 3 },
new Object[] { STRING_LLONG, "ABCDEFGH", 0 },
new Object[] { STRING_LLONG, "EFGH", 4 },
new Object[] { STRING_LLONG, "EFGHI", -1 },
new Object[] { STRING_U1, "\uFF21", 0 },
new Object[] { STRING_U1, "\uFF21A", -1 },
new Object[] { STRING_U2, "\uFF21\uFF22", 0 },
new Object[] { STRING_U2, "\uFF22", 1 },
new Object[] { STRING_U2, "A\uFF22", -1 },
new Object[] { STRING_M12, "\uFF21A", 0 },
new Object[] { STRING_M12, "A", 1 },
new Object[] { STRING_M12, "\uFF21\uFF21", -1 },
new Object[] { STRING_M11, "A\uFF21", 0 },
new Object[] { STRING_M11, "\uFF21", 1 },
new Object[] { STRING_M11, "A", 0 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
0 },
new Object[] { STRING_UDUPLICATE,
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21", 1 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21",
-1 }, };
}
@Test(dataProvider = "provider3")
public void testIndexOf(String str, String anotherString, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.indexOf(anotherString),
expected,
String.format(
"testing String(%s).indexOf(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
@DataProvider
public Object[][] provider4() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", 0, -1 },
new Object[] { STRING_L1, "A", 0, 0 },
new Object[] { STRING_L1, "A", 1, -1 },
new Object[] { STRING_L1, "AB", 0, -1 },
new Object[] { STRING_L2, "A", 0, 0 },
new Object[] { STRING_L2, "B", 0, 1 },
new Object[] { STRING_L2, "AB", 0, 0 },
new Object[] { STRING_L2, "AB", 1, -1 },
new Object[] { STRING_L4, "ABCD", 0, 0 },
new Object[] { STRING_L4, "BC", 0, 1 },
new Object[] { STRING_L4, "A", 0, 0 },
new Object[] { STRING_L4, "CD", 0, 2 },
new Object[] { STRING_L4, "A", 2, -1 },
new Object[] { STRING_L4, "ABCDE", 0, -1 },
new Object[] { STRING_LLONG, "ABCDEFGH", 0, 0 },
new Object[] { STRING_LLONG, "DEFGH", 0, 3 },
new Object[] { STRING_LLONG, "A", 0, 0 },
new Object[] { STRING_LLONG, "GHI", 0, -1 },
new Object[] { STRING_U1, "\uFF21", 0, 0 },
new Object[] { STRING_U1, "\uFF21A", 0, -1 },
new Object[] { STRING_U2, "\uFF21\uFF22", 0, 0 },
new Object[] { STRING_U2, "\uFF22", 0, 1 },
new Object[] { STRING_U2, "\uFF21", 1, -1 },
new Object[] { STRING_M12, "\uFF21A", 0, 0 },
new Object[] { STRING_M12, "A", 1, 1 },
new Object[] { STRING_M12, "\uFF21A", 1, -1 },
new Object[] { STRING_M12, "\uFF21", 0, 0 },
new Object[] { STRING_M11, "A\uFF21", 0, 0 },
new Object[] { STRING_M11, "\uFF21", 1, 1 },
new Object[] { STRING_M11, "A\uFF21", 1, -1 },
new Object[] { STRING_M11, "A\uFF21A", 0, -1 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
0, 0 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
1, -1 },
new Object[] {
STRING_UDUPLICATE,
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
1, 1 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
4, 4 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
7, -1 }, };
}
@Test(dataProvider = "provider4")
public void testIndexOf(String str, String anotherString, int fromIndex,
int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.indexOf(anotherString, fromIndex),
expected,
String.format(
"testing String(%s).indexOf(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
fromIndex, source));
});
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.intern.
* @run testng/othervm -XX:+CompactStrings Intern
* @run testng/othervm -XX:-CompactStrings Intern
*/
public class Intern extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "" },
new Object[] { STRING_L1, "A" },
new Object[] { STRING_LLONG, "ABCDEFGH" },
new Object[] { STRING_U1, "\uFF21" },
new Object[] { STRING_U2, "\uFF21\uFF22" },
new Object[] { STRING_M12, "\uFF21A" },
new Object[] { STRING_M11, "A\uFF21" },
new Object[] { STRING_MDUPLICATE1,
"\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A" }, };
}
@Test(dataProvider = "provider")
public void testIntern(String str, String expected) {
map.get(str).forEach(
(source, data) -> {
assertTrue(data.intern() == expected, String.format(
"testing String(%s).intern(), source : %s, ",
escapeNonASCIIs(data), source));
});
}
}

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.lastIndexOf.
* @run testng/othervm -XX:+CompactStrings LastIndexOf
* @run testng/othervm -XX:-CompactStrings LastIndexOf
*/
public class LastIndexOf extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, (int) 'A', -1 },
new Object[] { STRING_L1, (int) 'A', 0 },
new Object[] { STRING_L2, (int) 'A', 0 },
new Object[] { STRING_L2, (int) 'B', 1 },
new Object[] { STRING_L4, (int) 'A', 0 },
new Object[] { STRING_L4, (int) 'D', 3 },
new Object[] { STRING_LLONG, (int) 'A', 0 },
new Object[] { STRING_LLONG, (int) 'H', 7 },
new Object[] { STRING_U1, (int) '\uFF21', 0 },
new Object[] { STRING_U1, (int) 'B', -1 },
new Object[] { STRING_U2, (int) '\uFF21', 0 },
new Object[] { STRING_U2, (int) '\uFF22', 1 },
new Object[] { STRING_M12, (int) '\uFF21', 0 },
new Object[] { STRING_M12, (int) 'A', 1 },
new Object[] { STRING_M11, (int) 'A', 0 },
new Object[] { STRING_M11, (int) '\uFF21', 1 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF22', 9 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF21', 8 },
new Object[] { STRING_SUPPLEMENTARY,
Character.toCodePoint('\uD801', '\uDC01'), 2 }, };
}
@Test(dataProvider = "provider")
public void testLastIndexOf(String str, int ch, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.lastIndexOf(ch),
expected,
String.format(
"testing String(%s).lastIndexOf(%d), source : %s, ",
escapeNonASCIIs(data), ch, source));
});
}
@DataProvider
public Object[][] provider2() {
return new Object[][] {
new Object[] { STRING_EMPTY, (int) 'A', 0, -1 },
new Object[] { STRING_L1, (int) 'A', 0, 0 },
new Object[] { STRING_L1, (int) 'A', 1, 0 },
new Object[] { STRING_L2, (int) 'A', 0, 0 },
new Object[] { STRING_L2, (int) 'B', 1, 1 },
new Object[] { STRING_L2, (int) 'B', 2, 1 },
new Object[] { STRING_L4, (int) 'A', 0, 0 },
new Object[] { STRING_L4, (int) 'C', 2, 2 },
new Object[] { STRING_L4, (int) 'C', 1, -1 },
new Object[] { STRING_LLONG, (int) 'A', 0, 0 },
new Object[] { STRING_LLONG, (int) 'H', 7, 7 },
new Object[] { STRING_LLONG, (int) 'H', 6, -1 },
new Object[] { STRING_U1, (int) '\uFF21', 0, 0 },
new Object[] { STRING_U1, (int) '\uFF21', 7, 0 },
new Object[] { STRING_U2, (int) '\uFF21', 0, 0 },
new Object[] { STRING_U2, (int) '\uFF22', 0, -1 },
new Object[] { STRING_M12, (int) '\uFF21', 0, 0 },
new Object[] { STRING_M12, (int) 'A', 1, 1 },
new Object[] { STRING_M12, (int) 'A', 0, -1 },
new Object[] { STRING_M11, (int) 'A', 0, 0 },
new Object[] { STRING_M11, (int) '\uFF21', 1, 1 },
new Object[] { STRING_M11, (int) '\uFF21', 0, -1 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF21', 5, 4 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF21', 6, 6 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF22', 5, 5 },
new Object[] { STRING_UDUPLICATE, (int) '\uFF22', 6, 5 }, };
}
@Test(dataProvider = "provider2")
public void testLastIndexOf(String str, int ch, int fromIndex, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.lastIndexOf(ch, fromIndex),
expected,
String.format(
"testing String(%s).lastIndexOf(%d, %d), source : %s, ",
escapeNonASCIIs(data), ch,
fromIndex, source));
});
}
@DataProvider
public Object[][] provider3() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", -1 },
new Object[] { STRING_L1, "A", 0 },
new Object[] { STRING_L1, "AB", -1 },
new Object[] { STRING_L2, "AB", 0 },
new Object[] { STRING_L2, "B", 1 },
new Object[] { STRING_L4, "ABCD", 0 },
new Object[] { STRING_L4, "B", 1 },
new Object[] { STRING_LLONG, "ABCD", 0 },
new Object[] { STRING_LLONG, "GH", 6 },
new Object[] { STRING_U1, "\uFF21", 0 },
new Object[] { STRING_U1, "\uFF22", -1 },
new Object[] { STRING_U2, "\uFF21\uFF22", 0 },
new Object[] { STRING_U2, "\uFF22", 1 },
new Object[] { STRING_M12, "\uFF21A", 0 },
new Object[] { STRING_M12, "A", 1 },
new Object[] { STRING_M11, "A\uFF21", 0 },
new Object[] { STRING_M11, "\uFF21", 1 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22", 6 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22", 8 }, };
}
@Test(dataProvider = "provider3")
public void testLastIndexOf(String str, String anotherString, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.lastIndexOf(anotherString),
expected,
String.format(
"testing String(%s).lastIndexOf(%s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
source));
});
}
@DataProvider
public Object[][] provider4() {
return new Object[][] {
new Object[] { STRING_EMPTY, "A", 0, -1 },
new Object[] { STRING_L2, "AB", 0, 0 },
new Object[] { STRING_L1, "AB", -1, -1 },
new Object[] { STRING_L2, "B", 1, 1 },
new Object[] { STRING_L2, "B", 0, -1 },
new Object[] { STRING_L4, "ABC", 3, 0 },
new Object[] { STRING_L4, "ABC", 0, 0 },
new Object[] { STRING_L4, "ABC", 1, 0 },
new Object[] { STRING_L4, "BC", 1, 1 },
new Object[] { STRING_L4, "BC", 0, -1 },
new Object[] { STRING_LLONG, "ABCDEFGH", 0, 0 },
new Object[] { STRING_LLONG, "EFGH", 7, 4 },
new Object[] { STRING_LLONG, "EFGH", 3, -1 },
new Object[] { STRING_U1, "\uFF21", 0, 0 },
new Object[] { STRING_U1, "\uFF21", 7, 0 },
new Object[] { STRING_U2, "\uFF21\uFF22", 0, 0 },
new Object[] { STRING_U2, "\uFF21\uFF22", 1, 0 },
new Object[] { STRING_M12, "\uFF21A", 0, 0 },
new Object[] { STRING_M12, "A", 1, 1 },
new Object[] { STRING_M12, "A", 0, -1 },
new Object[] { STRING_M11, "A\uFF21", 0, 0 },
new Object[] { STRING_M11, "A\uFF21", 1, 0 },
new Object[] { STRING_M11, "\uFF21", 0, -1 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
9, 0 },
new Object[] {
STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
0, 0 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22", 6, 6 },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21", 6, 6 }, };
}
@Test(dataProvider = "provider4")
public void testLastIndexOf(String str, String anotherString,
int fromIndex, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.lastIndexOf(anotherString, fromIndex),
expected,
String.format(
"testing String(%s).lastIndexOf(%s, %d), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(anotherString),
fromIndex, source));
});
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.length.
* @run testng/othervm -XX:+CompactStrings Length
* @run testng/othervm -XX:-CompactStrings Length
*/
public class Length extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, 0 }, new Object[] { STRING_L1, 1 },
new Object[] { STRING_L2, 2 },
new Object[] { STRING_LLONG, 8 },
new Object[] { STRING_U1, 1 }, new Object[] { STRING_U2, 2 },
new Object[] { STRING_M12, 2 }, new Object[] { STRING_M11, 2 },
new Object[] { STRING_UDUPLICATE, 10 },
new Object[] { STRING_SUPPLEMENTARY, 6 }, };
}
@Test(dataProvider = "provider")
public void testLength(String str, int expected) {
map.get(str).forEach(
(source, data) -> {
assertEquals(data.length(), expected, String.format(
"testing String(%s).length(), source : %s, ",
escapeNonASCIIs(data), source));
});
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is testing
* Integer/Long's methods related to String.
* @run testng/othervm -XX:+CompactStrings Numbers
* @run testng/othervm -XX:-CompactStrings Numbers
*/
public class Numbers {
/*
* Data provider for testIntegerLong
*
* @return input parameter for testIntegerLong
*/
@DataProvider
public Object[][] numbers() {
return new Object[][] {
{ Integer.toBinaryString(Integer.MAX_VALUE),
"1111111111111111111111111111111" },
{ Integer.toBinaryString(Integer.MIN_VALUE),
"10000000000000000000000000000000" },
{ Integer.toBinaryString(7), "111" },
{ Integer.toBinaryString(0), "0" },
{ Integer.toOctalString(Integer.MAX_VALUE), "17777777777" },
{ Integer.toOctalString(Integer.MIN_VALUE), "20000000000" },
{ Integer.toOctalString(9), "11" },
{ Integer.toOctalString(0), "0" },
{ Integer.toHexString(Integer.MAX_VALUE), "7fffffff" },
{ Integer.toHexString(Integer.MIN_VALUE), "80000000" },
{ Integer.toHexString(17), "11" },
{ Integer.toHexString(0), "0" },
{ Integer.toString(Integer.MAX_VALUE, 2),
"1111111111111111111111111111111" },
{ Integer.toString(Integer.MIN_VALUE, 2),
"-10000000000000000000000000000000" },
{ Integer.toString(7, 2), "111" },
{ Integer.toString(0, 2), "0" },
{ Integer.toString(Integer.MAX_VALUE, 8), "17777777777" },
{ Integer.toString(Integer.MIN_VALUE, 8), "-20000000000" },
{ Integer.toString(9, 8), "11" },
{ Integer.toString(Integer.MAX_VALUE, 16), "7fffffff" },
{ Integer.toString(Integer.MIN_VALUE, 16), "-80000000" },
{ Integer.toString(17, 16), "11" },
{ Long.toBinaryString(Long.MAX_VALUE),
"111111111111111111111111111111111111111111111111111111111111111" },
{ Long.toBinaryString(Long.MIN_VALUE),
"1000000000000000000000000000000000000000000000000000000000000000" },
{ Long.toOctalString(Long.MAX_VALUE), "777777777777777777777" },
{ Long.toOctalString(Long.MIN_VALUE), "1000000000000000000000" },
{ Long.toHexString(Long.MAX_VALUE), "7fffffffffffffff" },
{ Long.toHexString(Long.MIN_VALUE), "8000000000000000" },
{ Long.toString(Long.MAX_VALUE, 2),
"111111111111111111111111111111111111111111111111111111111111111" },
{ Long.toString(Long.MIN_VALUE, 2),
"-1000000000000000000000000000000000000000000000000000000000000000" },
{ Long.toString(Long.MAX_VALUE, 8), "777777777777777777777" },
{ Long.toString(Long.MIN_VALUE, 8), "-1000000000000000000000" },
{ Long.toString(Long.MAX_VALUE, 16), "7fffffffffffffff" },
{ Long.toString(Long.MIN_VALUE, 16), "-8000000000000000" } };
}
/*
* test Integer/Long's methods related to String.
*
* @param res
* real result
* @param expected
* expected result
*/
@Test(dataProvider = "numbers")
public void testIntegerLong(String res, String expected) {
assertEquals(res, expected);
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.offsetByCodePoints.
* @run testng/othervm -XX:+CompactStrings OffsetByCodePoints
* @run testng/othervm -XX:-CompactStrings OffsetByCodePoints
*/
public class OffsetByCodePoints extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_SUPPLEMENTARY, 0, 1, 2 },
new Object[] { STRING_SUPPLEMENTARY, 0, 3, 5 },
new Object[] { STRING_SUPPLEMENTARY, 1, 1, 2 },
new Object[] { STRING_SUPPLEMENTARY, 1, 3, 5 },
new Object[] { STRING_SUPPLEMENTARY, 2, 1, 4 },
new Object[] { STRING_SUPPLEMENTARY, 2, 2, 5 },
new Object[] { STRING_SUPPLEMENTARY, 2, 3, 6 },
new Object[] { STRING_SUPPLEMENTARY, 3, 1, 4 },
new Object[] { STRING_SUPPLEMENTARY, 3, 2, 5 },
new Object[] { STRING_SUPPLEMENTARY, 3, 3, 6 }, };
}
@Test(dataProvider = "provider")
public void testOffsetByCodePoints(String str, int index,
int codePointOffset, int expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.offsetByCodePoints(index,
codePointOffset),
expected,
String.format(
"testing String(%s).offsetByCodePoints(%d, %d), source : %s, ",
escapeNonASCIIs(data), index,
codePointOffset, source));
});
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.regionMatches.
* @run testng/othervm -XX:+CompactStrings RegionMatches
* @run testng/othervm -XX:-CompactStrings RegionMatches
*/
public class RegionMatches extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, true, 0, "", 0, 0, true },
new Object[] { STRING_EMPTY, true, 0, "", 0, 1, false },
new Object[] { STRING_EMPTY, true, 0, "A", 0, 0, true },
new Object[] { STRING_EMPTY, true, 0, "", 0, 0, true },
new Object[] { STRING_EMPTY, true, 0, "", 0, 1, false },
new Object[] { STRING_L1, false, 0, "a", 0, 1, false },
new Object[] { STRING_L1, false, 0, "BA", 1, 1, true },
new Object[] { STRING_L1, false, 0, "Ba", 1, 1, false },
new Object[] { STRING_L1, true, 0, "a", 0, 1, true },
new Object[] { STRING_L1, true, 0, "BA", 1, 1, true },
new Object[] { STRING_L1, true, 0, "Ba", 1, 1, true },
new Object[] { STRING_L2, true, 1, "b", 0, 1, true },
new Object[] { STRING_L2, true, 1, "B", 0, 1, true },
new Object[] { STRING_L2, true, 0, "xaBc", 1, 2, true },
new Object[] { STRING_L2, false, 0, "AB", 0, 2, true },
new Object[] { STRING_L2, false, 0, "Ab", 0, 2, false },
new Object[] { STRING_L2, false, 1, "BAB", 2, 1, true },
new Object[] { STRING_LLONG, true, 1, "bCdEF", 0, 5, true },
new Object[] { STRING_LLONG, false, 2, "CDEFG", 0, 5, true },
new Object[] { STRING_LLONG, true, 2, "CDEFg", 0, 5, true },
new Object[] { STRING_U1, true, 0, "\uFF41", 0, 1, true },
new Object[] { STRING_U1, false, 0, "\uFF41", 0, 1, false },
new Object[] { STRING_MDUPLICATE1, true, 0, "\uFF41a\uFF41", 0,
3, true },
new Object[] { STRING_MDUPLICATE1, false, 0, "\uFF21a\uFF21",
0, 3, false },
new Object[] { STRING_SUPPLEMENTARY, true, 1, "\uDC00\uD801",
0, 2, true },
new Object[] { STRING_SUPPLEMENTARY, true, 4, "\uFF21", 0, 1,
true },
new Object[] { STRING_SUPPLEMENTARY, true, 5, "A", 0, 1, true },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, false, 0,
"\uD801\uDC28\uD801\uDC29", 0, 4, true },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, true, 1,
"\uDC28\uD801", 0, 2, true },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, true, 1,
"\uDC00\uD801", 0, 2, false },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, true, 4,
"\uFF21", 0, 1, true },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, false, 4,
"\uFF21", 0, 1, false },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, false, 4,
"\uFF41", 0, 1, true }, };
}
@Test(dataProvider = "provider")
public void testRegionMatches(String str, boolean ignoreCase, int toffset,
String other, int ooffset, int len, boolean expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.regionMatches(ignoreCase, toffset,
other, ooffset, len),
expected,
String.format(
"testing String(%s).regionMatches(%b, %d, %s, %d, %d), source : %s, ",
escapeNonASCIIs(data), ignoreCase,
toffset, escapeNonASCIIs(other),
ooffset, len, source));
});
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.replace.
* @run testng/othervm -XX:+CompactStrings Replace
* @run testng/othervm -XX:-CompactStrings Replace
*/
public class Replace extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_L1, 'A', 'B', "B" },
new Object[] { STRING_L1, 'A', 'A', "A" },
new Object[] { STRING_L1, 'A', '\uFF21', "\uFF21" },
new Object[] { STRING_L2, 'A', 'B', "BB" },
new Object[] { STRING_L2, 'B', 'A', "AA" },
new Object[] { STRING_L2, 'C', 'A', "AB" },
new Object[] { STRING_L2, 'B', '\uFF21', "A\uFF21" },
new Object[] { STRING_U1, '\uFF21', 'A', "A" },
new Object[] { STRING_U1, '\uFF22', 'A', "\uFF21" },
new Object[] { STRING_U2, '\uFF22', 'A', "\uFF21A" },
new Object[] { STRING_M12, 'A', '\uFF21', "\uFF21\uFF21" },
new Object[] { STRING_M11, '\uFF21', 'A', "AA" },
new Object[] { STRING_UDUPLICATE, '\uFF21', 'A',
"A\uFF22A\uFF22A\uFF22A\uFF22A\uFF22" },
new Object[] { STRING_MDUPLICATE1, '\uFF21', 'A', "AAAAAAAAAA" },
new Object[] { STRING_MDUPLICATE1, 'A', '\uFF21',
"\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21" }, };
}
@Test(dataProvider = "provider")
public void testReplace(String str, char oldChar, char newChar,
String expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.replace(oldChar, newChar),
expected,
String.format(
"testing String(%s).replace(%s, %s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCII(oldChar),
escapeNonASCII(newChar), source));
});
}
@DataProvider
public Object[][] provider2() {
return new Object[][] {
new Object[] { STRING_EMPTY, "", "ABC", "ABC" },
new Object[] { STRING_EMPTY, "", "", "" },
new Object[] { STRING_L1, "A", "B", "B" },
new Object[] { STRING_L1, "A", "A", "A" },
new Object[] { STRING_L2, "B", "\uFF21", "A\uFF21" },
new Object[] { STRING_LLONG, "BCD", "\uFF21", "A\uFF21EFGH" },
new Object[] { STRING_U1, "\uFF21", "A", "A" },
new Object[] { STRING_U1, "\uFF21", "A\uFF21", "A\uFF21" },
new Object[] { STRING_U2, "\uFF21", "A", "A\uFF22" },
new Object[] { STRING_U2, "\uFF22", "A", "\uFF21A" },
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22", "AB",
"ABABABABAB" },
new Object[] { STRING_MDUPLICATE1, "\uFF21", "A", "AAAAAAAAAA" },
new Object[] { STRING_MDUPLICATE1, "A", "\uFF21",
"\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21\uFF21" }, };
}
@Test(dataProvider = "provider2")
public void testReplace(String str, CharSequence target,
CharSequence replacement, String expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.replace(target, replacement),
expected,
String.format(
"testing String(%s).replace(%s, %s), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(target.toString()),
escapeNonASCIIs(replacement
.toString()), source));
});
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static jdk.testlibrary.SerializationUtils.*;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @library /lib/testlibrary
* @build jdk.testlibrary.SerializationUtils
* @summary Tests Compact String. This one is testing String serialization
* among -XX:+CompactStrings/-XX:-CompactStrings/LegacyString
* @run testng/othervm -XX:+CompactStrings SerializationTest
* @run testng/othervm -XX:-CompactStrings SerializationTest
*/
public class SerializationTest {
@DataProvider
public Object[][] provider() {
return new Object[][] {
// every byte array is serialized from corresponding String object
// by previous JDK(build 1.8.0_45-b14).
new Object[] { "", new byte[] { -84, -19, 0, 5, 116, 0, 0 } },
new Object[] { "A", new byte[] { -84, -19, 0, 5, 116, 0, 1, 65 } },
new Object[] { "AB", new byte[] { -84, -19, 0, 5, 116, 0, 2, 65, 66 } },
new Object[] { "abcdefghijk",
new byte[] {-84, -19, 0, 5, 116, 0, 11, 97, 98, 99, 100, 101,
102, 103, 104, 105, 106, 107 } },
new Object[] { "\uff21", new byte[] { -84, -19, 0, 5, 116, 0, 3, -17, -68, -95 } },
new Object[] { "\uff21\uff22", new byte[] { -84, -19, 0, 5, 116, 0, 6, -17, -68,
-95, -17, -68, -94 } },
new Object[] { "\uff21A\uff21A\uff21A\uff21A\uff21A",
new byte[] { -84, -19, 0, 5, 116, 0, 20, -17, -68, -95, 65, -17, -68,
-95, 65, -17, -68, -95, 65, -17, -68, -95, 65, -17, -68, -95, 65 } },
new Object[] { "A\uff21B\uff22C\uff23D\uff24E\uff25F\uff26G\uff27H\uff28",
new byte[] { -84, -19, 0, 5, 116, 0, 32, 65, -17, -68, -95, 66, -17, -68,
-94, 67, -17, -68, -93, 68, -17, -68, -92, 69, -17, -68, -91, 70, -17,
-68, -90, 71, -17, -68, -89, 72, -17, -68, -88 } },
new Object[] { "\uff21A\uff22B\uff23C\uff24D\uff25E\uff26F\uff27G\uff28H",
new byte[] { -84, -19, 0, 5, 116, 0, 32, -17, -68, -95, 65, -17, -68,
-94, 66, -17, -68, -93, 67, -17, -68, -92, 68, -17, -68, -91, 69, -17,
-68, -90, 70, -17, -68, -89, 71, -17, -68, -88, 72 } },
new Object[] { "\ud801\udc00\ud801\udc01\uff21A",
new byte[] { -84, -19, 0, 5, 116, 0, 16, -19, -96, -127, -19, -80, -128,
-19, -96, -127, -19, -80, -127, -17, -68, -95, 65 } },
new Object[] { "\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22",
new byte[] { -84, -19, 0, 5, 116, 0, 30, -17, -68, -95, -17, -68, -94, -17,
-68, -95, -17, -68, -94, -17, -68, -95, -17, -68, -94, -17, -68, -95, -17,
-68, -94, -17, -68, -95, -17, -68, -94 } } };
}
/*
* Verify serialization works between Compact String/Legacy String
*/
@Test(dataProvider = "provider")
public void test(String strContent, byte[] baInJDK8) throws Exception {
// Serialize a String object into byte array.
byte[] ba = serialize(strContent);
assertEquals(ba, baInJDK8);
// Deserialize a String object from byte array which is generated by previous JDK(build 1.8.0_45-b14).
Object obj = deserialize(ba);
assertEquals(obj.getClass(), String.class);
assertEquals((String)obj, strContent);
}
}

View File

@ -0,0 +1,181 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.split.
* @run testng/othervm -XX:+CompactStrings Split
* @run testng/othervm -XX:-CompactStrings Split
*/
public class Split extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_L1, "", 0, new String[] { "A" } },
new Object[] { STRING_L1, "", 1, new String[] { "A" } },
new Object[] { STRING_L1, "", 2, new String[] { "A", "" } },
new Object[] { STRING_L1, "A", 0, new String[] {} },
new Object[] { STRING_L2, "A", 0, new String[] { "", "B" } },
new Object[] { STRING_L2, "B", 0, new String[] { "A" } },
new Object[] { STRING_LLONG, "D", 0,
new String[] { "ABC", "EFGH" } },
new Object[] { STRING_LLONG, "[D]", 0,
new String[] { "ABC", "EFGH" } },
new Object[] { STRING_LLONG, "CD", 0,
new String[] { "AB", "EFGH" } },
new Object[] { STRING_LLONG, "DC", 0,
new String[] { "ABCDEFGH" } },
new Object[] { STRING_LLONG, "[CF]", 0,
new String[] { "AB", "DE", "GH" } },
new Object[] { STRING_LLONG, "[CF]", 1,
new String[] { "ABCDEFGH" } },
new Object[] { STRING_LLONG, "[CF]", 2,
new String[] { "AB", "DEFGH" } },
new Object[] { STRING_LLONG, "[FC]", 0,
new String[] { "AB", "DE", "GH" } },
new Object[] { STRING_LLONG, "[FC]", 1,
new String[] { "ABCDEFGH" } },
new Object[] { STRING_LLONG, "[FC]", 2,
new String[] { "AB", "DEFGH" } },
new Object[] { STRING_U1, "", 0, new String[] { "\uFF21" } },
new Object[] { STRING_U1, "", 1, new String[] { "\uFF21" } },
new Object[] { STRING_U1, "", 2, new String[] { "\uFF21", "" } },
new Object[] { STRING_U1, "\uFF21", 0, new String[] {} },
new Object[] { STRING_M12, "\uFF21", 0,
new String[] { "", "A" } },
new Object[] { STRING_M12, "A", 0, new String[] { "\uFF21" } },
new Object[] {
STRING_UDUPLICATE,
"\uFF21",
0,
new String[] { "", "\uFF22", "\uFF22", "\uFF22",
"\uFF22", "\uFF22" } },
new Object[] {
STRING_UDUPLICATE,
"\uFF21",
2,
new String[] { "",
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22" } },
new Object[] {
STRING_UDUPLICATE,
"\uFF21",
4,
new String[] { "", "\uFF22", "\uFF22",
"\uFF22\uFF21\uFF22\uFF21\uFF22" } },
new Object[] {
STRING_UDUPLICATE,
"\uFF22",
0,
new String[] { "\uFF21", "\uFF21", "\uFF21", "\uFF21",
"\uFF21" } },
new Object[] {
STRING_UDUPLICATE,
"\uFF22",
3,
new String[] { "\uFF21", "\uFF21",
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22" } },
new Object[] { STRING_MDUPLICATE1, "\uFF21", 0,
new String[] { "", "A", "A", "A", "A", "A" } },
new Object[] { STRING_MDUPLICATE1, "\uFF21", 3,
new String[] { "", "A", "A\uFF21A\uFF21A\uFF21A" } },
new Object[] {
STRING_MDUPLICATE1,
"A",
0,
new String[] { "\uFF21", "\uFF21", "\uFF21", "\uFF21",
"\uFF21" } },
new Object[] {
STRING_MDUPLICATE1,
"A",
4,
new String[] { "\uFF21", "\uFF21", "\uFF21",
"\uFF21A\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "\uD801\uDC01", 0,
new String[] { "\uD801\uDC00", "\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "\uDC01", 0,
new String[] { "\uD801\uDC00\uD801\uDC01\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "\uD801\uDC01", 0,
new String[] { "\uD801\uDC00", "\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uD801\uDC01\uFF21]", 0,
new String[] { "\uD801\uDC00", "", "A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uD801\uDC01\uFF21]", 1,
new String[] { "\uD801\uDC00\uD801\uDC01\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uD801\uDC01\uFF21]", 2,
new String[] { "\uD801\uDC00", "\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uFF21\uD801\uDC01]", 0,
new String[] { "\uD801\uDC00", "", "A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uFF21\uD801\uDC01]", 1,
new String[] { "\uD801\uDC00\uD801\uDC01\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY, "[\uFF21\uD801\uDC01]", 2,
new String[] { "\uD801\uDC00", "\uFF21A" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, "\uDC01", 0,
new String[] { "\uD801\uDC28\uD801\uDC29\uFF41a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE, "\uD801\uDC29",
0, new String[] { "\uD801\uDC28", "\uFF41a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uD801\uDC29\uFF41]", 0,
new String[] { "\uD801\uDC28", "", "a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uD801\uDC29\uFF41]", 1,
new String[] { "\uD801\uDC28\uD801\uDC29\uFF41a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uD801\uDC29\uFF41]", 2,
new String[] { "\uD801\uDC28", "\uFF41a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uFF41\uD801\uDC29]", 0,
new String[] { "\uD801\uDC28", "", "a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uFF41\uD801\uDC29]", 1,
new String[] { "\uD801\uDC28\uD801\uDC29\uFF41a" } },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"[\uFF41\uD801\uDC29]", 2,
new String[] { "\uD801\uDC28", "\uFF41a" } }, };
}
@Test(dataProvider = "provider")
public void testSplit(String str, String regex, int limit, String[] expected) {
map.get(str)
.forEach(
(source, data) -> {
assertTrue(
Arrays.equals(data.split(regex, limit),
expected),
String.format(
"testing String(%s).split(%s, %d), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(regex), limit,
source));
});
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.startsWith.
* @run testng/othervm -XX:+CompactStrings StartsWith
* @run testng/othervm -XX:-CompactStrings StartsWith
*/
public class StartsWith extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] {STRING_EMPTY, "", 0, true},
new Object[] {STRING_EMPTY, "A", 0, false},
new Object[] {STRING_EMPTY, "", 0, true},
new Object[] {STRING_EMPTY, "", -1, false},
new Object[] {STRING_L1, "A", 0, true},
new Object[] {STRING_L1, "A", -1, false},
new Object[] {STRING_L1, "A", 1, false},
new Object[] {STRING_L2, "B", 1, true},
new Object[] {STRING_L2, "B", 0, false},
new Object[] {STRING_L2, "A", 0, true},
new Object[] {STRING_L2, "AB", 1, false},
new Object[] {STRING_L4, "ABC", 0, true},
new Object[] {STRING_LLONG, "ABCDEFGH", 0, true},
new Object[] {STRING_LLONG, "ABCDE", 0, true},
new Object[] {STRING_LLONG, "CDE", 0, false},
new Object[] {STRING_LLONG, "FG", 5, true},
new Object[] {STRING_U1, "\uFF21", 0, true},
new Object[] {STRING_U1, "", 1, true},
new Object[] {STRING_U1, "\uFF21", 0, true},
new Object[] {STRING_U1, "A", 0, false},
new Object[] {STRING_U2, "\uFF21\uFF22", 0, true},
new Object[] {STRING_U2, "\uFF21", 0, true},
new Object[] {STRING_U2, "\uFF22", 0, false},
new Object[] {STRING_U2, "", 0, true},
new Object[] {STRING_M12, "\uFF21", 0, true},
new Object[] {STRING_M12, "\uFF21A", 0, true},
new Object[] {STRING_M12, "A", 0, false},
new Object[] {STRING_M12, "\uFF21A", 0, true},
new Object[] {STRING_M12, "A", 1, true},
new Object[] {STRING_M11, "A", 0, true},
new Object[] {STRING_M11, "A\uFF21", 0, true},
new Object[] {STRING_M11, "A\uFF21", 0, true},
new Object[] {STRING_M11, "\uFF21", 1, true},
new Object[] {STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
0, true},
new Object[] {STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22", 0, true},
new Object[] {STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22", 2, true},
new Object[] {STRING_UDUPLICATE,
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22", 5, false},
new Object[] {STRING_MDUPLICATE1,
"\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A", 0, true},
new Object[] {STRING_MDUPLICATE1,
"\uFF21A\uFF21A\uFF21A\uFF21A\uFF21", 0, true},
new Object[] {STRING_MDUPLICATE1, "A\uFF21A\uFF21A\uFF21A", 1, true},
new Object[] {STRING_SUPPLEMENTARY, "\uDC01\uFF21", 3, true},
};
}
@Test(dataProvider = "provider")
public void testStartsWith(String str, String prefix, int toffset,
boolean expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.startsWith(prefix, toffset),
expected,
String.format(
"testing String(%s).startsWith(%s, %d), source : %s, ",
escapeNonASCIIs(data),
escapeNonASCIIs(prefix), toffset,
source));
});
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.subString.
* @run testng/othervm -XX:+CompactStrings SubString
* @run testng/othervm -XX:-CompactStrings SubString
*/
public class SubString extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, 0, 0, "" },
new Object[] { STRING_L1, 0, 1, "A" },
new Object[] { STRING_L1, 1, 1, "" },
new Object[] { STRING_L2, 0, 2, "AB" },
new Object[] { STRING_L2, 1, 2, "B" },
new Object[] { STRING_LLONG, 0, 8, "ABCDEFGH" },
new Object[] { STRING_LLONG, 7, 8, "H" },
new Object[] { STRING_LLONG, 8, 8, "" },
new Object[] { STRING_LLONG, 3, 7, "DEFG" },
new Object[] { STRING_U1, 0, 1, "\uFF21" },
new Object[] { STRING_U1, 1, 1, "" },
new Object[] { STRING_U1, 0, 0, "" },
new Object[] { STRING_U2, 0, 2, "\uFF21\uFF22" },
new Object[] { STRING_U2, 1, 2, "\uFF22" },
new Object[] { STRING_U2, 2, 2, "" },
new Object[] { STRING_U2, 0, 2, "\uFF21\uFF22" },
new Object[] { STRING_U2, 1, 2, "\uFF22" },
new Object[] { STRING_M12, 1, 2, "A" },
new Object[] { STRING_M11, 0, 1, "A" },
new Object[] { STRING_M11, 1, 2, "\uFF21" },
new Object[] { STRING_UDUPLICATE, 1, 5,
"\uFF22\uFF21\uFF22\uFF21" },
new Object[] { STRING_MDUPLICATE1, 9, 10, "A" },
new Object[] { STRING_MDUPLICATE1, 7, 8, "A" }, };
}
@Test(dataProvider = "provider")
public void testSubstring(String str, int beginIndex, int endIndex,
String expected) {
map.get(str)
.forEach(
(source, data) -> {
assertEquals(
data.substring(beginIndex, endIndex),
expected,
String.format(
"testing String(%s).substring(%d, %d), source : %s, ",
escapeNonASCIIs(data), beginIndex,
endIndex, source));
});
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.toCharArray.
* @run testng/othervm -XX:+CompactStrings ToCharArray
* @run testng/othervm -XX:-CompactStrings ToCharArray
*/
public class ToCharArray extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, new char[] {} },
new Object[] { STRING_L1, new char[] { 'A' } },
new Object[] { STRING_L2, new char[] { 'A', 'B' } },
new Object[] { STRING_LLONG,
new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' } },
new Object[] { STRING_U1, new char[] { '\uFF21' } },
new Object[] { STRING_U2, new char[] { '\uFF21', '\uFF22' } },
new Object[] { STRING_M12, new char[] { '\uFF21', 'A' } },
new Object[] { STRING_M11, new char[] { 'A', '\uFF21' } }, };
}
@Test(dataProvider = "provider")
public void testToCharArray(String str, char[] expected) {
map.get(str)
.forEach(
(source, data) -> {
assertTrue(
Arrays.equals(data.toCharArray(), expected),
String.format(
"testing String(%s).toCharArray(), source : %s, ",
escapeNonASCIIs(data), source));
});
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.toLowerCase.
* @run testng/othervm -XX:+CompactStrings ToLowerCase
* @run testng/othervm -XX:-CompactStrings ToLowerCase
*/
public class ToLowerCase extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "" },
new Object[] { STRING_L1, "a" },
new Object[] { STRING_L2, "ab" },
new Object[] { STRING_U1, "\uFF41" },
new Object[] { STRING_MDUPLICATE1,
"\uFF41a\uFF41a\uFF41a\uFF41a\uFF41a" },
new Object[] { STRING_SUPPLEMENTARY,
"\uD801\uDC28\uD801\uDC29\uFF41a" },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"\uD801\uDC28\uD801\uDC29\uFF41a" },
new Object[] { STRING_SUPPLEMENTARY,
STRING_SUPPLEMENTARY_LOWERCASE } };
}
@Test(dataProvider = "provider")
public void testToLowerCase(String str, String expected) {
map.get(str).forEach(
(source, data) -> {
assertEquals(data.toLowerCase(), expected, String.format(
"testing String(%s).toLowerCase(), source : %s, ",
escapeNonASCIIs(data), source));
});
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.toUpperCase.
* @run testng/othervm -XX:+CompactStrings ToUpperCase
* @run testng/othervm -XX:-CompactStrings ToUpperCase
*/
public class ToUpperCase extends CompactString {
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] { STRING_EMPTY, "" },
new Object[] { STRING_L1, "A" },
new Object[] { STRING_L2, "AB" },
new Object[] { STRING_U1, "\uFF21" },
new Object[] { STRING_MDUPLICATE1,
"\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A" },
new Object[] { STRING_SUPPLEMENTARY,
"\uD801\uDC00\uD801\uDC01\uFF21A" },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
"\uD801\uDC00\uD801\uDC01\uFF21A" },
new Object[] { STRING_SUPPLEMENTARY_LOWERCASE,
STRING_SUPPLEMENTARY }, };
}
@Test(dataProvider = "provider")
public void testToUpperCase(String str, String expected) {
map.get(str).forEach(
(source, data) -> {
assertEquals(data.toUpperCase(), expected, String.format(
"testing String(%s).toUpperCase(), source : %s, ",
escapeNonASCIIs(data), source));
});
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.trim.
* @run testng/othervm -XX:+CompactStrings Trim
* @run testng/othervm -XX:-CompactStrings Trim
*/
public class Trim {
/*
* Data provider for testTrim
*
* @return input parameter for testTrim
*/
@DataProvider
public Object[][] trims() {
return new Object[][] {
{ " \t \t".trim(), "" },
{ "\t \t ".trim(), "" },
{ "\t A B C\t ".trim(), "A B C" },
{ " \t A B C \t".trim(), "A B C" },
{ "\t \uFF21 \uFF22 \uFF23\t ".trim(), "\uFF21 \uFF22 \uFF23" },
{ " \t \uFF21 \uFF22 \uFF23 \t".trim(), "\uFF21 \uFF22 \uFF23" },
{ " \t \uFF41 \uFF42 \uFF43 \t".trim(), "\uFF41 \uFF42 \uFF43" },
{ " \t A\uFF21 B\uFF22 C\uFF23 \t".trim(),
"A\uFF21 B\uFF22 C\uFF23" } };
}
/*
* test trim().
*
* @param res
* real result
* @param expected
* expected result
*/
@Test(dataProvider = "trims")
public void testTrim(String res, String expected) {
assertEquals(res, expected);
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.*;
import java.lang.reflect.Field;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is testing
* if Compact String enable/disable VM Options is indeed working in String class,
* it's verified by testing if the VM option affect coder and
* COMPACT_STRINGS field in String class.
* @run testng/othervm -XX:+CompactStrings -DCompactStringEnabled=true VMOptionsTest
* @run testng/othervm -XX:-CompactStrings -DCompactStringEnabled=false VMOptionsTest
* @run testng/othervm -DCompactStringEnabled=true VMOptionsTest
*/
public class VMOptionsTest {
boolean compactStringEnabled;
// corresponding "COMPACT_STRINGS" field in String class.
Field COMPACT_STRINGS;
// corresponding "coder" field in String class.
Field coder;
// corresponding coder type in String class.
final byte LATIN1 = 0;
final byte UTF16 = 1;
@BeforeClass
public void setUp() throws Exception {
compactStringEnabled = Boolean.valueOf(System.getProperty("CompactStringEnabled", null));
COMPACT_STRINGS = String.class.getDeclaredField("COMPACT_STRINGS");
COMPACT_STRINGS.setAccessible(true);
coder = String.class.getDeclaredField("coder");
coder.setAccessible(true);
}
@DataProvider
public Object[][] provider() {
return new Object[][] {
new Object[] {"", LATIN1},
new Object[] {"abc", LATIN1},
new Object[] {"A\uff21", UTF16},
new Object[] {"\uff21\uff22", UTF16}
};
}
/*
* verify the coder field in String objects.
*/
@Test(dataProvider = "provider")
public void testCoder(String str, byte expected) throws Exception {
byte c = (byte) coder.get(str);
expected = compactStringEnabled ? expected : UTF16;
assertEquals(c, expected);
}
/*
* verify the COMPACT_STRINGS flag in String objects.
*/
@Test(dataProvider = "provider")
public void testCompactStringFlag(String str, byte ignore) throws Exception {
assertTrue(COMPACT_STRINGS.get(str).equals(compactStringEnabled));
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This one is for String.valueOf.
* valueOf(char[] data) is not tested here.
* @run testng/othervm -XX:+CompactStrings ValueOf
* @run testng/othervm -XX:-CompactStrings ValueOf
*/
public class ValueOf {
/*
* Data provider for testValueOf
*
* @return input parameter for testValueOf
*/
@DataProvider
public Object[][] valueOfs() {
return new Object[][] { { String.valueOf(true), "true" },
{ String.valueOf(false), "false" },
{ String.valueOf(1.0f), "1.0" },
{ String.valueOf(0.0f), "0.0" },
{ String.valueOf(Float.MAX_VALUE), "3.4028235E38" },
{ String.valueOf(Float.MIN_VALUE), "1.4E-45" },
{ String.valueOf(1.0d), "1.0" },
{ String.valueOf(0.0d), "0.0" },
{ String.valueOf(Double.MAX_VALUE), "1.7976931348623157E308" },
{ String.valueOf(Double.MIN_VALUE), "4.9E-324" },
{ String.valueOf(1), "1" }, { String.valueOf(0), "0" },
{ String.valueOf(Integer.MAX_VALUE), "2147483647" },
{ String.valueOf(Integer.MIN_VALUE), "-2147483648" },
{ String.valueOf(1L), "1" }, { String.valueOf(0L), "0" },
{ String.valueOf(Long.MAX_VALUE), "9223372036854775807" },
{ String.valueOf(Long.MIN_VALUE), "-9223372036854775808" } };
}
/*
* test String.valueOf(xxx).
*
* @param res
* real result
* @param expected
* expected result
*/
@Test(dataProvider = "valueOfs")
public void testValueOf(String res, String expected) {
assertEquals(res, expected);
}
}

View File

@ -22,7 +22,7 @@
*/
/* @test
* @bug 8058779
* @bug 8058779 8054307
* @library /lib/testlibrary/
* @build jdk.testlibrary.RandomFactory
* @run testng LiteralReplace
@ -104,6 +104,109 @@ public class LiteralReplace {
{"abcdefgh", "[a-h]", "X", "abcdefgh"},
{"aa+", "a+", "", "a"},
{"^abc$", "abc", "x", "^x$"},
// more with non-latin1 characters
{"\u4e00\u4e00\u4e00",
"\u4e00\u4e00",
"\u4e01",
"\u4e01\u4e00"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08",
"\u4e03\u4e04\u4e05",
"\u4e10\u4e11\u4e12",
"\u4e00\u4e01\u4e02\u4e10\u4e11\u4e12\u4e06\u4e07\u4e08"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08",
"ABC",
"\u4e10\u4e11\u4e12",
"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e02\u4e03\u4e07\u4e08",
"\u4e02\u4e03",
"\u4e12\u4e13",
"\u4e00\u4e01\u4e12\u4e13\u4e04\u4e12\u4e13\u4e07\u4e08"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e02\u4e03\u4e07\u4e08",
"\u4e02\u4e03",
"ab",
"\u4e00\u4e01ab\u4e04ab\u4e07\u4e08"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07",
"",
"_",
"_\u4e00_\u4e01_\u4e02_\u4e03_\u4e04_\u4e05_\u4e06_\u4e07_"},
{"^\u4e00\u4e01\u4e02$",
"\u4e00\u4e01\u4e02",
"\u4e03",
"^\u4e03$"},
{"", "\u4e00", "\u4e01", ""},
{"", "", "\u4e00\u4e01\u4e02", "\u4e00\u4e01\u4e02"},
{"^\u4e00\u4e01\u4e02$",
"\u4e00\u4e01\u4e02",
"X",
"^X$"},
{"abcdefgh",
"def",
"\u4e01",
"abc\u4e01gh"},
{"abcdefgh",
"def",
"\u4e01\u4e02",
"abc\u4e01\u4e02gh"},
{"abcdefabcgh",
"abc",
"\u4e01\u4e02",
"\u4e01\u4e02def\u4e01\u4e02gh"},
{"abcdefabcghabc",
"abc",
"\u4e01\u4e02",
"\u4e01\u4e02def\u4e01\u4e02gh\u4e01\u4e02"},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05",
"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05",
"abcd",
"abcd"},
{"\u4e00\u4e01",
"\u4e00\u4e01",
"abcdefg",
"abcdefg"},
{"\u4e00\u4e01xyz",
"\u4e00\u4e01",
"abcdefg",
"abcdefgxyz"},
{"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00",
"\u4e00\u4e00",
"\u4e00\u4e00\u4e00",
"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00"},
{"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00",
"\u4e00\u4e00\u4e00",
"\u4e00\u4e00",
"\u4e00\u4e00\u4e00\u4e00"},
{"\u4e00.\u4e01.\u4e02.\u4e03.\u4e04.",
".",
"-",
"\u4e00-\u4e01-\u4e02-\u4e03-\u4e04-"},
{"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00",
"\u4e00",
"",
""},
{"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05",
"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05",
"",
""},
};
}

View File

@ -23,7 +23,7 @@
/*
@test
@bug 4217441 4533872 4900935 8020037 8032012 8041791 8042589
@bug 4217441 4533872 4900935 8020037 8032012 8041791 8042589 8054307
@summary toLowerCase should lower-case Greek Sigma correctly depending
on the context (final/non-final). Also it should handle
Locale specific (lt, tr, and az) lowercasings and supplementary
@ -134,14 +134,60 @@ public class ToLowerCase {
}
test(src.toString(), Locale.US, exp.toString());
// test latin1
src = new StringBuilder(0x100);
exp = new StringBuilder(0x100);
for (int cp = 0; cp < 0x100; cp++) {
int lowerCase = Character.toLowerCase(cp);
if (lowerCase == -1) { //Character.ERROR
continue;
}
src.appendCodePoint(cp);
exp.appendCodePoint(lowerCase);
}
test(src.toString(), Locale.US, exp.toString());
// test non-latin1 -> latin1
src = new StringBuilder(0x100).append("abc");
exp = new StringBuilder(0x100).append("abc");
for (int cp = 0x100; cp < 0x10000; cp++) {
int lowerCase = Character.toLowerCase(cp);
if (lowerCase < 0x100 && cp != '\u0130') {
src.appendCodePoint(cp);
exp.appendCodePoint(lowerCase);
}
}
test(src.toString(), Locale.US, exp.toString());
}
static void test(String in, Locale locale, String expected) {
test0(in, locale,expected);
for (String[] ss : new String[][] {
new String[] {"abc", "abc"},
new String[] {"aBc", "abc"},
new String[] {"ABC", "abc"},
new String[] {"ab\u4e00", "ab\u4e00"},
new String[] {"aB\u4e00", "ab\u4e00"},
new String[] {"AB\u4e00", "ab\u4e00"},
new String[] {"ab\uD800\uDC00", "ab\uD800\uDC00"},
new String[] {"aB\uD800\uDC00", "ab\uD800\uDC00"},
new String[] {"AB\uD800\uDC00", "ab\uD800\uDC00"},
new String[] {"ab\uD801\uDC1C", "ab\uD801\uDC44"},
new String[] {"aB\uD801\uDC1C", "ab\uD801\uDC44"},
new String[] {"AB\uD801\uDC1C", "ab\uD801\uDC44"},
}) {
test0(ss[0] + " " + in, locale, ss[1] + " " + expected);
test0(in + " " + ss[0], locale, expected + " " + ss[1]);
}
}
static void test0(String in, Locale locale, String expected) {
String result = in.toLowerCase(locale);
if (!result.equals(expected)) {
System.err.println("input: " + in + ", locale: " + locale +
", expected: " + expected + ", actual: " + result);
throw new RuntimeException();
}
}
}
}

View File

@ -23,7 +23,7 @@
/*
@test
@bug 4219630 4304573 4533872 4900935 8042589
@bug 4219630 4304573 4533872 4900935 8042589 8054307
@summary toUpperCase should upper-case German sharp s correctly even if
it's the only character in the string. should also uppercase
all of the 1:M char mappings correctly. Also it should handle
@ -97,14 +97,66 @@ public class ToUpperCase {
test("A\uD801\uDC44", Locale.ROOT, "A\uD801\uDC1c");
test("a\uD801\uDC28\uD801\uDC29\uD801\uDC2A", Locale.US, "A\uD801\uDC00\uD801\uDC01\uD801\uDC02");
test("A\uD801\uDC28a\uD801\uDC29b\uD801\uDC2Ac", Locale.US, "A\uD801\uDC00A\uD801\uDC01B\uD801\uDC02C");
// test latin1 only case
StringBuilder src = new StringBuilder(0x100);
StringBuilder exp = new StringBuilder(0x100);
for (int cp = 0; cp < 0x100; cp++) {
int upperCase = Character.toUpperCase(cp);
if (upperCase == -1) { //Character.ERROR
continue;
}
src.appendCodePoint(cp);
if (cp == '\u00df') {
exp.append("SS"); // need Character.toUpperCaseEx()
} else {
exp.appendCodePoint(upperCase);
}
}
test(src.toString(), Locale.US, exp.toString());
// test non-latin1 -> latin1
src = new StringBuilder(0x100).append("ABC");
exp = new StringBuilder(0x100).append("ABC");
for (int cp = 0x100; cp < 0x10000; cp++) {
int upperCase = Character.toUpperCase(cp);
if (upperCase < 0x100) {
src.appendCodePoint(cp);
exp.appendCodePoint(upperCase);
}
}
test(src.toString(), Locale.US, exp.toString());
}
static void test(String in, Locale locale, String expected) {
test0(in, locale,expected);
// trigger different code paths
for (String[] ss : new String[][] {
new String[] {"abc", "ABC"},
new String[] {"AbC", "ABC"},
new String[] {"ABC", "ABC"},
new String[] {"AB\u4e00", "AB\u4e00"},
new String[] {"ab\u4e00", "AB\u4e00"},
new String[] {"aB\u4e00", "AB\u4e00"},
new String[] {"AB\uD800\uDC00", "AB\uD800\uDC00"},
new String[] {"Ab\uD800\uDC00", "AB\uD800\uDC00"},
new String[] {"ab\uD800\uDC00", "AB\uD800\uDC00"},
new String[] {"AB\uD801\uDC44", "AB\uD801\uDC1C"},
new String[] {"Ab\uD801\uDC44", "AB\uD801\uDC1C"},
new String[] {"ab\uD801\uDC44", "AB\uD801\uDC1C"},
}) {
test0(ss[0] + " " + in, locale, ss[1] + " " + expected);
test0(in + " " + ss[0], locale, expected + " " + ss[1]);
}
}
static void test0(String in, Locale locale, String expected) {
String result = in.toUpperCase(locale);
if (!result.equals(expected)) {
System.err.println("input: " + in + ", locale: " + locale +
", expected: " + expected + ", actual: " + result);
throw new RuntimeException();
}
}
}
}

View File

@ -0,0 +1,489 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8077559
* @summary Tests Compact String. This test is testing StringBuffer
* behavior related to Compact String.
* @run testng/othervm -XX:+CompactStrings CompactStringBuffer
* @run testng/othervm -XX:-CompactStrings CompactStringBuffer
*/
public class CompactStringBuffer {
/*
* Tests for "A"
*/
@Test
public void testCompactStringBufferForLatinA() {
final String ORIGIN = "A";
/*
* Because right now ASCII is the default encoding parameter for source
* code in JDK build environment, so we escape them. same as below.
*/
check(new StringBuffer(ORIGIN).append(new char[] { '\uFF21' }),
"A\uFF21");
check(new StringBuffer(ORIGIN).append(new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuffer(ORIGIN).append("\uFF21"), "A\uFF21");
check(new StringBuffer(ORIGIN).append(new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuffer(ORIGIN).delete(0, 1), "");
check(new StringBuffer(ORIGIN).delete(0, 0), "A");
check(new StringBuffer(ORIGIN).deleteCharAt(0), "");
assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), 0);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), -1);
assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
assertEquals(new StringBuffer(ORIGIN).insert(1, "\uD801\uDC00")
.indexOf("A", 0), 0);
assertEquals(new StringBuffer(ORIGIN).insert(0, "\uD801\uDC00")
.indexOf("A", 0), 2);
check(new StringBuffer(ORIGIN).insert(0, new char[] {}), "A");
check(new StringBuffer(ORIGIN).insert(1, new char[] { '\uFF21' }),
"A\uFF21");
check(new StringBuffer(ORIGIN).insert(0, new char[] { '\uFF21' }),
"\uFF21A");
check(new StringBuffer(ORIGIN).insert(0, new StringBuffer("\uFF21")),
"\uFF21A");
check(new StringBuffer(ORIGIN).insert(1, new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuffer(ORIGIN).insert(0, ""), "A");
check(new StringBuffer(ORIGIN).insert(0, "\uFF21"), "\uFF21A");
check(new StringBuffer(ORIGIN).insert(1, "\uFF21"), "A\uFF21");
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), -1);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 1);
check(new StringBuffer(ORIGIN).replace(0, 0, "\uFF21"), "\uFF21A");
check(new StringBuffer(ORIGIN).replace(0, 1, "\uFF21"), "\uFF21");
checkSetCharAt(new StringBuffer(ORIGIN), 0, '\uFF21', "\uFF21");
checkSetLength(new StringBuffer(ORIGIN), 0, "");
checkSetLength(new StringBuffer(ORIGIN), 1, "A");
check(new StringBuffer(ORIGIN).substring(0), "A");
check(new StringBuffer(ORIGIN).substring(1), "");
}
/*
* Tests for "\uFF21"
*/
@Test
public void testCompactStringBufferForNonLatinA() {
final String ORIGIN = "\uFF21";
check(new StringBuffer(ORIGIN).append(new char[] { 'A' }), "\uFF21A");
check(new StringBuffer(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
check(new StringBuffer(ORIGIN).append("A"), "\uFF21A");
check(new StringBuffer(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
check(new StringBuffer(ORIGIN).delete(0, 1), "");
check(new StringBuffer(ORIGIN).delete(0, 0), "\uFF21");
check(new StringBuffer(ORIGIN).deleteCharAt(0), "");
assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), -1);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), 0);
assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
check(new StringBuffer(ORIGIN).insert(0, new char[] {}), "\uFF21");
check(new StringBuffer(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21A");
check(new StringBuffer(ORIGIN).insert(0, new char[] { 'A' }), "A\uFF21");
check(new StringBuffer(ORIGIN).insert(0, new StringBuffer("A")),
"A\uFF21");
check(new StringBuffer(ORIGIN).insert(1, new StringBuffer("A")),
"\uFF21A");
check(new StringBuffer(ORIGIN).insert(0, ""), "\uFF21");
check(new StringBuffer(ORIGIN).insert(0, "A"), "A\uFF21");
check(new StringBuffer(ORIGIN).insert(1, "A"), "\uFF21A");
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), -1);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 0);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 1);
check(new StringBuffer(ORIGIN).replace(0, 0, "A"), "A\uFF21");
check(new StringBuffer(ORIGIN).replace(0, 1, "A"), "A");
checkSetCharAt(new StringBuffer(ORIGIN), 0, 'A', "A");
checkSetLength(new StringBuffer(ORIGIN), 0, "");
checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
check(new StringBuffer(ORIGIN).substring(0), "\uFF21");
check(new StringBuffer(ORIGIN).substring(1), "");
}
/*
* Tests for "\uFF21A"
*/
@Test
public void testCompactStringBufferForMixedA1() {
final String ORIGIN = "\uFF21A";
check(new StringBuffer(ORIGIN).delete(0, 1), "A");
check(new StringBuffer(ORIGIN).delete(1, 2), "\uFF21");
check(new StringBuffer(ORIGIN).deleteCharAt(1), "\uFF21");
check(new StringBuffer(ORIGIN).deleteCharAt(0), "A");
assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), 1);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), 0);
assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
check(new StringBuffer(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21AA");
check(new StringBuffer(ORIGIN).insert(0, new char[] { '\uFF21' }),
"\uFF21\uFF21A");
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 1);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 0);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 2);
check(new StringBuffer(ORIGIN).replace(0, 0, "A"), "A\uFF21A");
check(new StringBuffer(ORIGIN).replace(0, 1, "A"), "AA");
checkSetCharAt(new StringBuffer(ORIGIN), 0, 'A', "AA");
checkSetLength(new StringBuffer(ORIGIN), 0, "");
checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
check(new StringBuffer(ORIGIN).substring(0), "\uFF21A");
check(new StringBuffer(ORIGIN).substring(1), "A");
}
/*
* Tests for "A\uFF21"
*/
@Test
public void testCompactStringBufferForMixedA2() {
final String ORIGIN = "A\uFF21";
check(new StringBuffer(ORIGIN).replace(1, 2, "A"), "AA");
checkSetLength(new StringBuffer(ORIGIN), 1, "A");
check(new StringBuffer(ORIGIN).substring(0), "A\uFF21");
check(new StringBuffer(ORIGIN).substring(1), "\uFF21");
check(new StringBuffer(ORIGIN).substring(0, 1), "A");
}
/*
* Tests for "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A"
*/
@Test
public void testCompactStringBufferForDuplicatedMixedA1() {
final String ORIGIN = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
assertEquals(new StringBuffer(ORIGIN).indexOf("A", 5), 5);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 5), 6);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 9);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 8);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 10);
check(new StringBuffer(ORIGIN).substring(9), "A");
check(new StringBuffer(ORIGIN).substring(8), "\uFF21A");
}
/*
* Tests for "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21"
*/
@Test
public void testCompactStringBufferForDuplicatedMixedA2() {
final String ORIGIN = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
checkSetLength(new StringBuffer(ORIGIN), 1, "A");
assertEquals(new StringBuffer(ORIGIN).indexOf("A", 5), 6);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 5), 5);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 8);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 9);
check(new StringBuffer(ORIGIN).substring(9), "\uFF21");
check(new StringBuffer(ORIGIN).substring(8), "A\uFF21");
}
/*
* Tests for "\uD801\uDC00\uD801\uDC01"
*/
@Test
public void testCompactStringForSupplementaryCodePoint() {
final String ORIGIN = "\uD801\uDC00\uD801\uDC01";
check(new StringBuffer(ORIGIN).append("A"), "\uD801\uDC00\uD801\uDC01A");
check(new StringBuffer(ORIGIN).append("\uFF21"),
"\uD801\uDC00\uD801\uDC01\uFF21");
check(new StringBuffer(ORIGIN).appendCodePoint('A'),
"\uD801\uDC00\uD801\uDC01A");
check(new StringBuffer(ORIGIN).appendCodePoint('\uFF21'),
"\uD801\uDC00\uD801\uDC01\uFF21");
assertEquals(new StringBuffer(ORIGIN).charAt(0), '\uD801');
assertEquals(new StringBuffer(ORIGIN).codePointAt(0),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuffer(ORIGIN).codePointAt(1),
Character.codePointAt(ORIGIN, 1));
assertEquals(new StringBuffer(ORIGIN).codePointBefore(2),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
check(new StringBuffer(ORIGIN).delete(0, 2), "\uD801\uDC01");
check(new StringBuffer(ORIGIN).delete(0, 3), "\uDC01");
check(new StringBuffer(ORIGIN).deleteCharAt(1), "\uD801\uD801\uDC01");
checkGetChars(new StringBuffer(ORIGIN), 0, 3, new char[] { '\uD801',
'\uDC00', '\uD801' });
assertEquals(new StringBuffer(ORIGIN).indexOf("\uD801\uDC01"), 2);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uDC01"), 3);
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21"), -1);
assertEquals(new StringBuffer(ORIGIN).indexOf("A"), -1);
check(new StringBuffer(ORIGIN).insert(0, "\uFF21"),
"\uFF21\uD801\uDC00\uD801\uDC01");
check(new StringBuffer(ORIGIN).insert(1, "\uFF21"),
"\uD801\uFF21\uDC00\uD801\uDC01");
check(new StringBuffer(ORIGIN).insert(1, "A"),
"\uD801A\uDC00\uD801\uDC01");
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uDC00\uD801"), 1);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uD801"), 2);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), -1);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), -1);
assertEquals(new StringBuffer(ORIGIN).length(), 4);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 2);
check(new StringBuffer(ORIGIN).replace(0, 2, "A"), "A\uD801\uDC01");
check(new StringBuffer(ORIGIN).replace(0, 3, "A"), "A\uDC01");
check(new StringBuffer(ORIGIN).replace(0, 2, "\uFF21"),
"\uFF21\uD801\uDC01");
check(new StringBuffer(ORIGIN).replace(0, 3, "\uFF21"), "\uFF21\uDC01");
check(new StringBuffer(ORIGIN).reverse(), "\uD801\uDC01\uD801\uDC00");
checkSetCharAt(new StringBuffer(ORIGIN), 1, '\uDC01',
"\uD801\uDC01\uD801\uDC01");
checkSetCharAt(new StringBuffer(ORIGIN), 1, 'A', "\uD801A\uD801\uDC01");
checkSetLength(new StringBuffer(ORIGIN), 2, "\uD801\uDC00");
checkSetLength(new StringBuffer(ORIGIN), 3, "\uD801\uDC00\uD801");
check(new StringBuffer(ORIGIN).substring(1, 3), "\uDC00\uD801");
}
/*
* Tests for "A\uD801\uDC00\uFF21"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed1() {
final String ORIGIN = "A\uD801\uDC00\uFF21";
assertEquals(new StringBuffer(ORIGIN).codePointBefore(3),
Character.codePointAt(ORIGIN, 1));
assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), '\uD801');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), 'A');
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 2);
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 4), 3);
check(new StringBuffer(ORIGIN).delete(0, 1), "\uD801\uDC00\uFF21");
check(new StringBuffer(ORIGIN).delete(0, 1).delete(2, 3), "\uD801\uDC00");
check(new StringBuffer(ORIGIN).deleteCharAt(3).deleteCharAt(0),
"\uD801\uDC00");
assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21"), 3);
assertEquals(new StringBuffer(ORIGIN).indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 3);
assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 3);
check(new StringBuffer(ORIGIN).replace(1, 3, "A"), "AA\uFF21");
check(new StringBuffer(ORIGIN).replace(1, 4, "A"), "AA");
check(new StringBuffer(ORIGIN).replace(1, 4, ""), "A");
check(new StringBuffer(ORIGIN).reverse(), "\uFF21\uD801\uDC00A");
checkSetLength(new StringBuffer(ORIGIN), 1, "A");
check(new StringBuffer(ORIGIN).substring(0, 1), "A");
}
/*
* Tests for "\uD801\uDC00\uFF21A"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed2() {
final String ORIGIN = "\uD801\uDC00\uFF21A";
assertEquals(new StringBuffer(ORIGIN).codePointBefore(3),
Character.codePointAt(ORIGIN, 2));
assertEquals(new StringBuffer(ORIGIN).codePointBefore(2),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), '\uD801');
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 2);
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 4), 3);
check(new StringBuffer(ORIGIN).delete(0, 2), "\uFF21A");
check(new StringBuffer(ORIGIN).delete(0, 3), "A");
check(new StringBuffer(ORIGIN).deleteCharAt(0).deleteCharAt(0)
.deleteCharAt(0), "A");
assertEquals(new StringBuffer(ORIGIN).indexOf("A"), 3);
assertEquals(new StringBuffer(ORIGIN).delete(0, 3).indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).replace(0, 3, "B").indexOf("A"),
1);
assertEquals(new StringBuffer(ORIGIN).substring(3, 4).indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 2);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuffer(ORIGIN).replace(0, 3, "B"), "BA");
check(new StringBuffer(ORIGIN).reverse(), "A\uFF21\uD801\uDC00");
}
/*
* Tests for "\uD801A\uDC00\uFF21"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed3() {
final String ORIGIN = "\uD801A\uDC00\uFF21";
assertEquals(new StringBuffer(ORIGIN).codePointAt(1), 'A');
assertEquals(new StringBuffer(ORIGIN).codePointAt(3), '\uFF21');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), '\uD801');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), 'A');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(3), '\uDC00');
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 3);
assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
assertEquals(new StringBuffer(ORIGIN).delete(0, 1).delete(1, 3)
.indexOf("A"), 0);
assertEquals(
new StringBuffer(ORIGIN).replace(0, 1, "B").replace(2, 4, "C")
.indexOf("A"), 1);
assertEquals(new StringBuffer(ORIGIN).substring(1, 4).substring(0, 1)
.indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuffer(ORIGIN).reverse(), "\uFF21\uDC00A\uD801");
}
/*
* Tests for "A\uDC01\uFF21\uD801"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed4() {
final String ORIGIN = "A\uDC01\uFF21\uD801";
assertEquals(new StringBuffer(ORIGIN).codePointAt(1), '\uDC01');
assertEquals(new StringBuffer(ORIGIN).codePointAt(3), '\uD801');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), 'A');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), '\uDC01');
assertEquals(new StringBuffer(ORIGIN).codePointBefore(3), '\uFF21');
assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 3);
assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
assertEquals(new StringBuffer(ORIGIN).delete(1, 4).indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).replace(1, 4, "B").indexOf("A"),
0);
assertEquals(new StringBuffer(ORIGIN).substring(0, 1).indexOf("A"), 0);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuffer(ORIGIN).reverse(), "\uD801\uFF21\uDC01A");
}
@Test
public void testCompactStringMisc() {
String ascii = "abcdefgh";
String asciiMixed = "abc" + "\u4e00\u4e01\u4e02" + "fgh";
String bmp = "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08";
String bmpMixed = "\u4e00\u4e01\u4e02" + "ABC" + "\u4e06\u4e07\u4e08";
check(new StringBuffer().append(ascii).delete(0, 20).toString(),
"");
check(new StringBuffer().append(ascii).delete(3, 20).toString(),
"abc");
check(new StringBuffer().append(ascii).delete(3, 6).toString(),
"abcgh");
check(new StringBuffer().append(ascii).deleteCharAt(0).toString(),
"bcdefgh");
check(new StringBuffer().append(ascii).deleteCharAt(3).toString(),
"abcefgh");
check(new StringBuffer().append(asciiMixed).delete(3, 6).toString(),
"abcfgh");
check(new StringBuffer().append(asciiMixed).deleteCharAt(3).toString(),
"abc\u4e01\u4e02fgh");
check(new StringBuffer().append(asciiMixed).deleteCharAt(3)
.deleteCharAt(3)
.deleteCharAt(3).toString(),
"abcfgh");
check(new StringBuffer().append(bmp).delete(0, 20).toString(),
"");
check(new StringBuffer().append(bmp).delete(3, 20).toString(),
"\u4e00\u4e01\u4e02");
check(new StringBuffer().append(bmp).delete(3, 6).toString(),
"\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
check(new StringBuffer().append(bmp).deleteCharAt(0).toString(),
"\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08");
check(new StringBuffer().append(bmp).deleteCharAt(3).toString(),
"\u4e00\u4e01\u4e02\u4e04\u4e05\u4e06\u4e07\u4e08");
check(new StringBuffer().append(bmpMixed).delete(3, 6).toString(),
"\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
////////////////////////////////////////////////////////////////////
check(new StringBuffer().append(ascii).replace(3, 6, "AB").toString(),
"abcABgh");
check(new StringBuffer().append(asciiMixed).replace(3, 6, "AB").toString(),
"abcABfgh");
check(new StringBuffer().append(bmp).replace(3, 6, "AB").toString(),
"\u4e00\u4e01\u4e02AB\u4e06\u4e07\u4e08");
check(new StringBuffer().append(bmpMixed).replace(3, 6, "").toString(),
"\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
check(new StringBuffer().append(ascii).replace(3, 6, "\u4e01\u4e02").toString(),
"abc\u4e01\u4e02gh");
////////////////////////////////////////////////////////////////////
check(new StringBuffer().append(ascii).insert(3, "").toString(),
"abcdefgh");
check(new StringBuffer().append(ascii).insert(3, "AB").toString(),
"abcABdefgh");
check(new StringBuffer().append(ascii).insert(3, "\u4e01\u4e02").toString(),
"abc\u4e01\u4e02defgh");
check(new StringBuffer().append(asciiMixed).insert(0, 'A').toString(),
"Aabc\u4e00\u4e01\u4e02fgh");
check(new StringBuffer().append(asciiMixed).insert(3, "A").toString(),
"abcA\u4e00\u4e01\u4e02fgh");
check(new StringBuffer().append(ascii).insert(3, 1234567).toString(),
"abc1234567defgh");
check(new StringBuffer().append(bmp).insert(3, 1234567).toString(),
"\u4e00\u4e01\u4e021234567\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08");
////////////////////////////////////////////////////////////////////
check(new StringBuffer().append(ascii).append(1.23456).toString(),
"abcdefgh1.23456");
check(new StringBuffer().append(bmp).append(1.23456).toString(),
"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e081.23456");
}
private void checkGetChars(StringBuffer sb, int srcBegin, int srcEnd,
char expected[]) {
char[] dst = new char[srcEnd - srcBegin];
sb.getChars(srcBegin, srcEnd, dst, 0);
assertTrue(Arrays.equals(dst, expected));
}
private void checkSetCharAt(StringBuffer sb, int index, char ch,
String expected) {
sb.setCharAt(index, ch);
check(sb, expected);
}
private void checkSetLength(StringBuffer sb, int newLength, String expected) {
sb.setLength(newLength);
check(sb, expected);
}
private void check(StringBuffer sb, String expected) {
check(sb.toString(), expected);
}
private void check(String str, String expected) {
assertTrue(str.equals(expected), String.format(
"Get (%s) but expect (%s), ", escapeNonASCIIs(str),
escapeNonASCIIs(expected)));
}
/*
* Because right now system default charset in JPRT environment is only
* guaranteed to support ASCII characters in log, so we escape them.
*/
private String escapeNonASCIIs(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c > 0x7F) {
sb.append("\\u").append(Integer.toHexString((int) c));
} else {
sb.append(c);
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static jdk.testlibrary.SerializationUtils.*;
import static org.testng.Assert.*;
/*
* @test
* @bug 8077559
* @library /lib/testlibrary
* @build jdk.testlibrary.SerializationUtils
* @summary Tests Compact String. This one is testing StringBuffer serialization
* among -XX:+CompactStrings/-XX:-CompactStrings/LegacyStringBuffer
* @run testng/othervm -XX:+CompactStrings CompactStringBufferSerialization
* @run testng/othervm -XX:-CompactStrings CompactStringBufferSerialization
*/
public class CompactStringBufferSerialization {
@DataProvider
public Object[][] provider() {
return new Object[][] {
// every byte array is serialized from corresponding StringBuilder object
// by previous JDK(build 1.8.0_45-b14).
new Object[] {
new StringBuffer(""),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 0, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 1, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("AB"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 2, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, 0, 65, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("abcdefghijk"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 11, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 27, 0, 97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0, 105, 0,
106, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\uff21"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 1, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, -1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\uff21\uff22"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 2, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, -1, 33, -1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\uff21A\uff21A\uff21A\uff21A\uff21A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 10, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("A\uff21B\uff22C\uff23D\uff24E\uff25F\uff26G\uff27H\uff28"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 16, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, 0, 65, -1, 33, 0, 66, -1, 34, 0, 67, -1, 35, 0, 68, -1, 36, 0, 69, -1, 37,
0, 70, -1, 38, 0, 71, -1, 39, 0, 72, -1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\uff21A\uff22B\uff23C\uff24D\uff25E\uff26F\uff27G\uff28H"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 16, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, -1, 33, 0, 65, -1, 34, 0, 66, -1, 35, 0, 67, -1, 36, 0, 68, -1, 37, 0, 69,
-1, 38, 0, 70, -1, 39, 0, 71, -1, 40, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\ud801\udc00\ud801\udc01\uff21A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 6, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 22, -40, 1, -36, 0, -40, 1, -36, 1, -1, 33, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuffer("\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 22, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 102,
102, 101, 114, 47, 7, 7, -39, -22, -56, -22, -45, 3, 0, 3, 73, 0, 5, 99, 111, 117, 110, 116, 90, 0, 6, 115, 104, 97, 114, 101,
100, 91, 0, 5, 118, 97, 108, 117, 101, 116, 0, 2, 91, 67, 120, 112, 0, 0, 0, 10, 0, 117, 114, 0, 2, 91, 67, -80, 38, 102, -80,
-30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1,
34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } } };
}
/*
* Verify serialization works between Compact StringBuffer/Legacy StringBuffer
*/
@Test(dataProvider = "provider")
public void test(StringBuffer sbContent, byte[] baInJDK8) throws Exception {
// Serialize a StringBuffer object into byte array.
byte[] ba = serialize(sbContent);
assertEquals(ba, baInJDK8);
// Deserialize a StringBuffer object from byte array which is generated by previous JDK(build 1.8.0_45-b14).
Object obj = deserialize(ba);
assertEquals(obj.getClass(), StringBuffer.class);
assertTrue(equals((StringBuffer)obj, sbContent));
}
boolean equals(StringBuffer sb, StringBuffer expected) {
if(sb.length() == expected.length()
&& sb.capacity() == expected.capacity()
&& sb.toString().equals(expected.toString())) {
return true;
}
return false;
}
}

View File

@ -94,7 +94,7 @@ public class Exceptions {
System.out.println("StringBuffer.replace(int start, int end, String str)");
tryCatch(" -1, 2, \" \"",
new StringIndexOutOfBoundsException(-1),
new StringIndexOutOfBoundsException("start -1, end 2, length 7"),
new Runnable() {
public void run() {
StringBuffer sb = new StringBuffer("hilbert");
@ -102,14 +102,14 @@ public class Exceptions {
}});
tryCatch(" 7, 8, \" \"",
new StringIndexOutOfBoundsException("start > length()"),
new StringIndexOutOfBoundsException("start 7, end 6, length 6"),
new Runnable() {
public void run() {
StringBuffer sb = new StringBuffer("banach");
sb.replace(7, 8, " ");
}});
tryCatch(" 2, 1, \" \"",
new StringIndexOutOfBoundsException("start > end"),
new StringIndexOutOfBoundsException("start 2, end 1, length 7"),
new Runnable() {
public void run() {
StringBuffer sb = new StringBuffer("riemann");

View File

@ -264,4 +264,3 @@ public class BuilderForwarding {
}
}
}

View File

@ -0,0 +1,414 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Arrays;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8054307 8077559
* @summary Tests Compact String. This test is testing StringBuilder
* behavior related to Compact String.
* @run testng/othervm -XX:+CompactStrings CompactStringBuilder
* @run testng/othervm -XX:-CompactStrings CompactStringBuilder
*/
public class CompactStringBuilder {
/*
* Tests for "A"
*/
@Test
public void testCompactStringBuilderForLatinA() {
final String ORIGIN = "A";
/*
* Because right now ASCII is the default encoding parameter for source
* code in JDK build environment, so we escape them. same as below.
*/
check(new StringBuilder(ORIGIN).append(new char[] { '\uFF21' }),
"A\uFF21");
check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuilder(ORIGIN).append("\uFF21"), "A\uFF21");
check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuilder(ORIGIN).delete(0, 1), "");
check(new StringBuilder(ORIGIN).delete(0, 0), "A");
check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 0);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), -1);
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
assertEquals(new StringBuilder(ORIGIN).insert(1, "\uD801\uDC00")
.indexOf("A", 0), 0);
assertEquals(new StringBuilder(ORIGIN).insert(0, "\uD801\uDC00")
.indexOf("A", 0), 2);
check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "A");
check(new StringBuilder(ORIGIN).insert(1, new char[] { '\uFF21' }),
"A\uFF21");
check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
"\uFF21A");
check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("\uFF21")),
"\uFF21A");
check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("\uFF21")),
"A\uFF21");
check(new StringBuilder(ORIGIN).insert(0, ""), "A");
check(new StringBuilder(ORIGIN).insert(0, "\uFF21"), "\uFF21A");
check(new StringBuilder(ORIGIN).insert(1, "\uFF21"), "A\uFF21");
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
check(new StringBuilder(ORIGIN).replace(0, 0, "\uFF21"), "\uFF21A");
check(new StringBuilder(ORIGIN).replace(0, 1, "\uFF21"), "\uFF21");
checkSetCharAt(new StringBuilder(ORIGIN), 0, '\uFF21', "\uFF21");
checkSetLength(new StringBuilder(ORIGIN), 0, "");
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
check(new StringBuilder(ORIGIN).substring(0), "A");
check(new StringBuilder(ORIGIN).substring(1), "");
}
/*
* Tests for "\uFF21"
*/
@Test
public void testCompactStringBuilderForNonLatinA() {
final String ORIGIN = "\uFF21";
check(new StringBuilder(ORIGIN).append(new char[] { 'A' }), "\uFF21A");
check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
check(new StringBuilder(ORIGIN).append("A"), "\uFF21A");
check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
check(new StringBuilder(ORIGIN).delete(0, 1), "");
check(new StringBuilder(ORIGIN).delete(0, 0), "\uFF21");
check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), -1);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "\uFF21");
check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21A");
check(new StringBuilder(ORIGIN).insert(0, new char[] { 'A' }), "A\uFF21");
check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("A")),
"A\uFF21");
check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("A")),
"\uFF21A");
check(new StringBuilder(ORIGIN).insert(0, ""), "\uFF21");
check(new StringBuilder(ORIGIN).insert(0, "A"), "A\uFF21");
check(new StringBuilder(ORIGIN).insert(1, "A"), "\uFF21A");
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21");
check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "A");
checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "A");
checkSetLength(new StringBuilder(ORIGIN), 0, "");
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
check(new StringBuilder(ORIGIN).substring(0), "\uFF21");
check(new StringBuilder(ORIGIN).substring(1), "");
}
/*
* Tests for "\uFF21A"
*/
@Test
public void testCompactStringBuilderForMixedA1() {
final String ORIGIN = "\uFF21A";
check(new StringBuilder(ORIGIN).delete(0, 1), "A");
check(new StringBuilder(ORIGIN).delete(1, 2), "\uFF21");
check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uFF21");
check(new StringBuilder(ORIGIN).deleteCharAt(0), "A");
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 1);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }),
"\uFF21AA");
check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
"\uFF21\uFF21A");
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 1);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 2);
check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21A");
check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "AA");
checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "AA");
checkSetLength(new StringBuilder(ORIGIN), 0, "");
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
check(new StringBuilder(ORIGIN).substring(0), "\uFF21A");
check(new StringBuilder(ORIGIN).substring(1), "A");
}
/*
* Tests for "A\uFF21"
*/
@Test
public void testCompactStringBuilderForMixedA2() {
final String ORIGIN = "A\uFF21";
check(new StringBuilder(ORIGIN).replace(1, 2, "A"), "AA");
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
check(new StringBuilder(ORIGIN).substring(0), "A\uFF21");
check(new StringBuilder(ORIGIN).substring(1), "\uFF21");
check(new StringBuilder(ORIGIN).substring(0, 1), "A");
}
/*
* Tests for "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A"
*/
@Test
public void testCompactStringBuilderForDuplicatedMixedA1() {
final String ORIGIN = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 5);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 6);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 9);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 8);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 10);
check(new StringBuilder(ORIGIN).substring(9), "A");
check(new StringBuilder(ORIGIN).substring(8), "\uFF21A");
}
/*
* Tests for "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21"
*/
@Test
public void testCompactStringBuilderForDuplicatedMixedA2() {
final String ORIGIN = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 6);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 5);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 8);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 9);
check(new StringBuilder(ORIGIN).substring(9), "\uFF21");
check(new StringBuilder(ORIGIN).substring(8), "A\uFF21");
}
/*
* Tests for "\uD801\uDC00\uD801\uDC01"
*/
@Test
public void testCompactStringForSupplementaryCodePoint() {
final String ORIGIN = "\uD801\uDC00\uD801\uDC01";
check(new StringBuilder(ORIGIN).append("A"), "\uD801\uDC00\uD801\uDC01A");
check(new StringBuilder(ORIGIN).append("\uFF21"),
"\uD801\uDC00\uD801\uDC01\uFF21");
check(new StringBuilder(ORIGIN).appendCodePoint('A'),
"\uD801\uDC00\uD801\uDC01A");
check(new StringBuilder(ORIGIN).appendCodePoint('\uFF21'),
"\uD801\uDC00\uD801\uDC01\uFF21");
assertEquals(new StringBuilder(ORIGIN).charAt(0), '\uD801');
assertEquals(new StringBuilder(ORIGIN).codePointAt(0),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuilder(ORIGIN).codePointAt(1),
Character.codePointAt(ORIGIN, 1));
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
check(new StringBuilder(ORIGIN).delete(0, 2), "\uD801\uDC01");
check(new StringBuilder(ORIGIN).delete(0, 3), "\uDC01");
check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uD801\uD801\uDC01");
checkGetChars(new StringBuilder(ORIGIN), 0, 3, new char[] { '\uD801',
'\uDC00', '\uD801' });
assertEquals(new StringBuilder(ORIGIN).indexOf("\uD801\uDC01"), 2);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uDC01"), 3);
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), -1);
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), -1);
check(new StringBuilder(ORIGIN).insert(0, "\uFF21"),
"\uFF21\uD801\uDC00\uD801\uDC01");
check(new StringBuilder(ORIGIN).insert(1, "\uFF21"),
"\uD801\uFF21\uDC00\uD801\uDC01");
check(new StringBuilder(ORIGIN).insert(1, "A"),
"\uD801A\uDC00\uD801\uDC01");
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uDC00\uD801"), 1);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uD801"), 2);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
assertEquals(new StringBuilder(ORIGIN).length(), 4);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
check(new StringBuilder(ORIGIN).replace(0, 2, "A"), "A\uD801\uDC01");
check(new StringBuilder(ORIGIN).replace(0, 3, "A"), "A\uDC01");
check(new StringBuilder(ORIGIN).replace(0, 2, "\uFF21"),
"\uFF21\uD801\uDC01");
check(new StringBuilder(ORIGIN).replace(0, 3, "\uFF21"), "\uFF21\uDC01");
check(new StringBuilder(ORIGIN).reverse(), "\uD801\uDC01\uD801\uDC00");
checkSetCharAt(new StringBuilder(ORIGIN), 1, '\uDC01',
"\uD801\uDC01\uD801\uDC01");
checkSetCharAt(new StringBuilder(ORIGIN), 1, 'A', "\uD801A\uD801\uDC01");
checkSetLength(new StringBuilder(ORIGIN), 2, "\uD801\uDC00");
checkSetLength(new StringBuilder(ORIGIN), 3, "\uD801\uDC00\uD801");
check(new StringBuilder(ORIGIN).substring(1, 3), "\uDC00\uD801");
}
/*
* Tests for "A\uD801\uDC00\uFF21"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed1() {
final String ORIGIN = "A\uD801\uDC00\uFF21";
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
Character.codePointAt(ORIGIN, 1));
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uD801');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
check(new StringBuilder(ORIGIN).delete(0, 1), "\uD801\uDC00\uFF21");
check(new StringBuilder(ORIGIN).delete(0, 1).delete(2, 3),
"\uD801\uDC00");
check(new StringBuilder(ORIGIN).deleteCharAt(3).deleteCharAt(0),
"\uD801\uDC00");
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), 3);
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 3);
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 3);
check(new StringBuilder(ORIGIN).replace(1, 3, "A"), "AA\uFF21");
check(new StringBuilder(ORIGIN).replace(1, 4, "A"), "AA");
check(new StringBuilder(ORIGIN).replace(1, 4, ""), "A");
check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uD801\uDC00A");
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
check(new StringBuilder(ORIGIN).substring(0, 1), "A");
}
/*
* Tests for "\uD801\uDC00\uFF21A"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed2() {
final String ORIGIN = "\uD801\uDC00\uFF21A";
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
Character.codePointAt(ORIGIN, 2));
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
Character.codePointAt(ORIGIN, 0));
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
check(new StringBuilder(ORIGIN).delete(0, 2), "\uFF21A");
check(new StringBuilder(ORIGIN).delete(0, 3), "A");
check(new StringBuilder(ORIGIN).deleteCharAt(0).deleteCharAt(0)
.deleteCharAt(0), "A");
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 3);
assertEquals(new StringBuilder(ORIGIN).delete(0, 3).indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).replace(0, 3, "B").indexOf("A"),
1);
assertEquals(new StringBuilder(ORIGIN).substring(3, 4).indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuilder(ORIGIN).replace(0, 3, "B"), "BA");
check(new StringBuilder(ORIGIN).reverse(), "A\uFF21\uD801\uDC00");
}
/*
* Tests for "\uD801A\uDC00\uFF21"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed3() {
final String ORIGIN = "\uD801A\uDC00\uFF21";
assertEquals(new StringBuilder(ORIGIN).codePointAt(1), 'A');
assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uFF21');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), 'A');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uDC00');
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
assertEquals(new StringBuilder(ORIGIN).delete(0, 1).delete(1, 3)
.indexOf("A"), 0);
assertEquals(
new StringBuilder(ORIGIN).replace(0, 1, "B").replace(2, 4, "C")
.indexOf("A"), 1);
assertEquals(new StringBuilder(ORIGIN).substring(1, 4).substring(0, 1)
.indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uDC00A\uD801");
}
/*
* Tests for "A\uDC01\uFF21\uD801"
*/
@Test
public void testCompactStringForSupplementaryCodePointMixed4() {
final String ORIGIN = "A\uDC01\uFF21\uD801";
assertEquals(new StringBuilder(ORIGIN).codePointAt(1), '\uDC01');
assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uD801');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uDC01');
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uFF21');
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
assertEquals(new StringBuilder(ORIGIN).delete(1, 4).indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).replace(1, 4, "B").indexOf("A"),
0);
assertEquals(new StringBuilder(ORIGIN).substring(0, 1).indexOf("A"), 0);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
check(new StringBuilder(ORIGIN).reverse(), "\uD801\uFF21\uDC01A");
}
private void checkGetChars(StringBuilder sb, int srcBegin, int srcEnd,
char expected[]) {
char[] dst = new char[srcEnd - srcBegin];
sb.getChars(srcBegin, srcEnd, dst, 0);
assertTrue(Arrays.equals(dst, expected));
}
private void checkSetCharAt(StringBuilder sb, int index, char ch,
String expected) {
sb.setCharAt(index, ch);
check(sb, expected);
}
private void checkSetLength(StringBuilder sb, int newLength, String expected) {
sb.setLength(newLength);
check(sb, expected);
}
private void check(StringBuilder sb, String expected) {
check(sb.toString(), expected);
}
private void check(String str, String expected) {
assertTrue(str.equals(expected), String.format(
"Get (%s) but expect (%s), ", escapeNonASCIIs(str),
escapeNonASCIIs(expected)));
}
/*
* Because right now system default charset in JPRT environment is only
* guaranteed to support ASCII characters in log, so we escape them.
*/
private String escapeNonASCIIs(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c > 0x7F) {
sb.append("\\u").append(Integer.toHexString((int) c));
} else {
sb.append(c);
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static jdk.testlibrary.SerializationUtils.*;
import static org.testng.Assert.*;
/*
* @test
* @bug 8077559
* @library /lib/testlibrary
* @build jdk.testlibrary.SerializationUtils
* @summary Tests Compact String. This one is testing StringBuilder serialization
* among -XX:+CompactStrings/-XX:-CompactStrings/LegacyStringBuilder
* @run testng/othervm -XX:+CompactStrings CompactStringBuilderSerialization
* @run testng/othervm -XX:-CompactStrings CompactStringBuilderSerialization
*/
public class CompactStringBuilderSerialization {
@DataProvider
public Object[][] provider() {
return new Object[][] {
// every byte array is serialized from corresponding StringBuffer object
// by previous JDK(build 1.8.0_45-b14).
new Object[] {
new StringBuilder(""),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 0, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 1, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("AB"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 2, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, 0, 65, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("abcdefghijk"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 11, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 27, 0, 97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0,
105, 0, 106, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\uff21"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 1, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, -1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\uff21\uff22"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 2, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, -1, 33, -1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\uff21A\uff21A\uff21A\uff21A\uff21A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 10, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1,
33, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("A\uff21B\uff22C\uff23D\uff24E\uff25F\uff26G\uff27H\uff28"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 16, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, 0, 65, -1, 33, 0, 66, -1, 34, 0, 67, -1, 35, 0, 68, -1, 36, 0,
69, -1, 37, 0, 70, -1, 38, 0, 71, -1, 39, 0, 72, -1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\uff21A\uff22B\uff23C\uff24D\uff25E\uff26F\uff27G\uff28H"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 16, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, -1, 33, 0, 65, -1, 34, 0, 66, -1, 35, 0, 67, -1, 36, 0, 68, -1,
37, 0, 69, -1, 38, 0, 70, -1, 39, 0, 71, -1, 40, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\ud801\udc00\ud801\udc01\uff21A"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 6, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 22, -40, 1, -36, 0, -40, 1, -36, 1, -1, 33, 0, 65, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
new Object[] {
new StringBuilder("\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22"),
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 10, 117, 114, 0, 2, 91, 67, -80, 38,
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34,
-1, 33, -1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } } };
}
/*
* Verify serialization works between Compact StringBuilder/Legacy StringBuilder
*/
@Test(dataProvider = "provider")
public void test(StringBuilder sbContent, byte[] baInJDK8) throws Exception {
// Serialize a StringBuilder object into byte array.
byte[] ba = serialize(sbContent);
assertEquals(ba, baInJDK8);
// Deserialize a StringBuilder object from byte array which is generated by previous JDK(build 1.8.0_45-b14).
Object obj = deserialize(ba);
assertEquals(obj.getClass(), StringBuilder.class);
assertTrue(equals((StringBuilder)obj, sbContent));
}
boolean equals(StringBuilder sb, StringBuilder expected) {
if(sb.length() == expected.length()
&& sb.capacity() == expected.capacity()
&& sb.toString().equals(expected.toString())) {
return true;
}
return false;
}
}

View File

@ -94,21 +94,21 @@ public class Exceptions {
System.out.println("StringBuilder.replace(int start, int end, String str)");
tryCatch(" -1, 2, \" \"",
new StringIndexOutOfBoundsException(-1),
new StringIndexOutOfBoundsException("start -1, end 2, length 7"),
new Runnable() {
public void run() {
StringBuilder sb = new StringBuilder("hilbert");
sb.replace(-1, 2, " ");
}});
tryCatch(" 7, 8, \" \"",
new StringIndexOutOfBoundsException("start > length()"),
new StringIndexOutOfBoundsException("start 7, end 6, length 6"),
new Runnable() {
public void run() {
StringBuilder sb = new StringBuilder("banach");
sb.replace(7, 8, " ");
}});
tryCatch(" 2, 1, \" \"",
new StringIndexOutOfBoundsException("start > end"),
new StringIndexOutOfBoundsException("start 2, end 1, length 7"),
new Runnable() {
public void run() {
StringBuilder sb = new StringBuilder("riemann");

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.testlibrary;
import java.io.*;
/**
* Common library for various test serialization utility functions.
*/
public final class SerializationUtils {
/*
* Serialize an object into byte array.
*/
public static byte[] serialize(Object obj) throws Exception {
try (ByteArrayOutputStream bs = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bs);) {
out.writeObject(obj);
return bs.toByteArray();
}
}
/*
* Deserialize an object from byte array.
*/
public static Object deserialize(byte[] ba) throws Exception {
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(ba));) {
return in.readObject();
}
}
}

View File

@ -22,7 +22,7 @@
*/
/* @test
* @bug 6636323 6636319 7040220 7096080 7183053 8080248
* @bug 6636323 6636319 7040220 7096080 7183053 8080248 8054307
* @summary Test if StringCoding and NIO result have the same de/encoding result
* @modules java.base/sun.nio.cs
* @run main/othervm/timeout=2000 TestStringCoding
@ -36,41 +36,61 @@ import java.nio.charset.*;
public class TestStringCoding {
public static void main(String[] args) throws Throwable {
// full bmp first
char[] bmp = new char[0x10000];
for (int i = 0; i < 0x10000; i++) {
bmp[i] = (char)i;
}
char[] latin = Arrays.copyOf(bmp, 0x100);
char[] ascii = Arrays.copyOf(bmp, 0x80);
byte[] latinBA = new byte[0x100];
for (int i = 0; i < 0x100; i++) {
latinBA[i] = (byte)i;
}
byte[] asciiBA = Arrays.copyOf(latinBA, 0x80);
for (Boolean hasSM: new boolean[] { false, true }) {
if (hasSM)
if (hasSM) {
System.setSecurityManager(new PermissiveSecurityManger());
}
for (Charset cs: Charset.availableCharsets().values()) {
if ("ISO-2022-CN".equals(cs.name()) ||
"x-COMPOUND_TEXT".equals(cs.name()) ||
"x-JISAutoDetect".equals(cs.name()))
continue;
System.out.printf("Testing(sm=%b) " + cs.name() + "....", hasSM);
// full bmp first
char[] bmpCA = new char[0x10000];
for (int i = 0; i < 0x10000; i++) {
bmpCA[i] = (char)i;
}
byte[] sbBA = new byte[0x100];
for (int i = 0; i < 0x100; i++) {
sbBA[i] = (byte)i;
}
test(cs, bmpCA, sbBA);
testNewString(cs, testGetBytes(cs, new String(bmp)));
testNewString(cs, testGetBytes(cs, new String(latin)));
testNewString(cs, testGetBytes(cs, new String(ascii)));
testGetBytes(cs, testNewString(cs, latinBA));
testGetBytes(cs, testNewString(cs, asciiBA));
// "randomed" sizes
Random rnd = new Random();
for (int i = 0; i < 10; i++) {
int clen = rnd.nextInt(0x10000);
int blen = rnd.nextInt(0x100);
//System.out.printf(" blen=%d, clen=%d%n", blen, clen);
test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen));
char[] bmp0 = Arrays.copyOf(bmp, rnd.nextInt(0x10000));
testNewString(cs, testGetBytes(cs, new String(bmp0)));
//add a pair of surrogates
int pos = clen / 2;
if ((pos + 1) < blen) {
bmpCA[pos] = '\uD800';
bmpCA[pos+1] = '\uDC00';
int pos = bmp0.length / 2;
if ((pos + 1) < bmp0.length) {
bmp0[pos] = '\uD800';
bmp0[pos+1] = '\uDC00';
}
test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen));
}
testNewString(cs, testGetBytes(cs, new String(bmp0)));
char[] latin0 = Arrays.copyOf(latin, rnd.nextInt(0x100));
char[] ascii0 = Arrays.copyOf(ascii, rnd.nextInt(0x80));
byte[] latinBA0 = Arrays.copyOf(latinBA, rnd.nextInt(0x100));
byte[] asciiBA0 = Arrays.copyOf(asciiBA, rnd.nextInt(0x80));
testNewString(cs, testGetBytes(cs, new String(latin0)));
testNewString(cs, testGetBytes(cs, new String(ascii0)));
testGetBytes(cs, testNewString(cs, latinBA0));
testGetBytes(cs, testNewString(cs, asciiBA0));
}
testSurrogates(cs);
testMixed(cs);
System.out.println("done!");
}
@ -109,8 +129,9 @@ public class TestStringCoding {
//getBytes(cs);
bmpBA = bmpStr.getBytes(cs);
if (!Arrays.equals(bmpBA, baNIO))
if (!Arrays.equals(bmpBA, baNIO)) {
throw new RuntimeException("getBytes(cs) failed -> " + cs.name());
}
//new String(csn);
String strSC = new String(bmpBA, cs.name());
@ -118,49 +139,61 @@ public class TestStringCoding {
if(!strNIO.equals(strSC)) {
throw new RuntimeException("new String(csn) failed -> " + cs.name());
}
//new String(cs);
strSC = new String(bmpBA, cs);
if (!strNIO.equals(strSC))
if (!strNIO.equals(strSC)) {
throw new RuntimeException("new String(cs) failed -> " + cs.name());
}
}
static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable {
String bmpStr = new String(bmpCA);
CharsetDecoder dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
static byte[] getBytes(CharsetEncoder enc, String str) throws Throwable {
ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(str.toCharArray()));
byte[] ba = new byte[bf.limit()];
bf.get(ba, 0, ba.length);
return ba;
}
static byte[] testGetBytes(Charset cs, String str) throws Throwable {
CharsetEncoder enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
//getBytes(csn);
byte[] baSC = bmpStr.getBytes(cs.name());
ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA));
byte[] baNIO = new byte[bf.limit()];
bf.get(baNIO, 0, baNIO.length);
if (!Arrays.equals(baSC, baNIO))
byte[] baSC = str.getBytes(cs.name());
byte[] baNIO = getBytes(enc, str);
if (!Arrays.equals(baSC, baNIO)) {
throw new RuntimeException("getBytes(csn) failed -> " + cs.name());
}
//getBytes(cs);
baSC = bmpStr.getBytes(cs);
if (!Arrays.equals(baSC, baNIO))
baSC = str.getBytes(cs);
if (!Arrays.equals(baSC, baNIO)) {
throw new RuntimeException("getBytes(cs) failed -> " + cs.name());
}
return baSC;
}
static String testNewString(Charset cs, byte[] ba) throws Throwable {
CharsetDecoder dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
//new String(csn);
String strSC = new String(sbBA, cs.name());
String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString();
if(!strNIO.equals(strSC))
String strSC = new String(ba, cs.name());
String strNIO = dec.reset().decode(ByteBuffer.wrap(ba)).toString();
if(!strNIO.equals(strSC)) {
throw new RuntimeException("new String(csn) failed -> " + cs.name());
}
//new String(cs);
strSC = new String(sbBA, cs);
if (!strNIO.equals(strSC))
throw new RuntimeException("new String(cs) failed -> " + cs.name());
strSC = new String(ba, cs);
if (!strNIO.equals(strSC)) {
throw new RuntimeException("new String(cs)/bmp failed -> " + cs.name());
}
return strSC;
}
static void testSurrogates(Charset cs) throws Throwable {
//encode unmappable surrogates
CharsetEncoder enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
if (enc instanceof sun.nio.cs.ArrayEncoder &&
cs.contains(Charset.forName("ASCII"))) {
if (cs.name().equals("UTF-8") || // utf8 handles surrogates

View File

@ -22,7 +22,7 @@
*/
/* @test
@bug 7040220
@bug 7040220 8054307
@summary Test if StringCoding and NIO result have the same de/encoding result for UTF-8
* @run main/othervm/timeout=2000 TestStringCodingUTF8
* @key randomness
@ -50,6 +50,18 @@ public class TestStringCodingUTF8 {
}
test(cs, bmp, 0, bmp.length);
char[] ascii = new char[0x80];
for (int i = 0; i < 0x80; i++) {
ascii[i] = (char)i;
}
test(cs, ascii, 0, ascii.length);
char[] latin1 = new char[0x100];
for (int i = 0; i < 0x100; i++) {
latin1[i] = (char)i;
}
test(cs, latin1, 0, latin1.length);
ArrayList<Integer> list = new ArrayList<>(0x20000);
for (int i = 0; i < 0x20000; i++) {
list.add(i, i);