Skip to content

Commit

Permalink
Refactor String model class
Browse files Browse the repository at this point in the history
Refactors String model class based on JDK 10.0.1 source.

* Add support for JEP 254: Compact Strings, which fixes
    [junit] java.lang.NoSuchFieldError: java.lang.String.COMPACT_STRINGS

* Refactor String#contentEquals(java.lang.CharSequence) as the current
implementation only handles UTF16
  • Loading branch information
gayanW committed Jul 22, 2018
1 parent 5145473 commit 1e0702b
Showing 1 changed file with 54 additions and 52 deletions.
106 changes: 54 additions & 52 deletions src/classes/modules/java.base/java/lang/String.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public final class String

private static final long serialVersionUID = -6849794470754667710L;

static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}

private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
Expand All @@ -79,18 +83,13 @@ public String(String original) {
}

public String(char value[]) {
this(value, 0, value.length, null);
this(value, 0, value.length);
}

public String(char value[], boolean share) {
this(value, 0, value.length, null);
}

public String(char value[], int offset, int count) {
String proxy=init(value,offset,count);
this.value=proxy.value;
this.coder=proxy.coder;
this.hash=proxy.hash;
}

private native String init(char[] value, int offset, int count);
Expand All @@ -99,7 +98,6 @@ public String(int[] codePoints, int offset, int count) {
String proxy=init(codePoints,offset,count);
this.value=proxy.value;
this.coder=proxy.coder;
this.hash=proxy.hash;
}

private native String init(int[] codePoints, int offset, int count);
Expand All @@ -119,13 +117,10 @@ public String(byte ascii[], int hibyte) {
this(ascii, hibyte, 0, ascii.length);
}



public String(byte bytes[], int offset, int length, String charsetName){
String proxy=init(bytes,offset,length,charsetName);
this.value=proxy.value;
this.coder=proxy.coder;
this.hash=proxy.hash;
}

private native String init(byte bytes[], int offset, int length, String charsetName);
Expand All @@ -151,8 +146,7 @@ public String(byte x[], int offset, int length, Charset cset) {
this.coder = result.coder;
}

public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
public String(byte bytes[], String charsetName) throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}

Expand All @@ -164,42 +158,30 @@ public String(byte bytes[], int offset, int length) {
String proxy=init(bytes,offset,length);
this.value=proxy.value;
this.coder=proxy.coder;
this.hash=proxy.hash;
}


private native String init(byte bytes[], int offset, int length);

public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}


public String(StringBuffer x) {
this(x.toString());
}


public String(StringBuilder x) {
this.value = Arrays.copyOf(x.getValue(), x.length());
this.coder = x.coder;
}

String(char[] value, int off, int len, Void sig) {
if (len == 0) {
this.value = "".value;
this.coder = "".coder;
} else {
byte[] val = StringUTF16.compress(value, off, len);
if (val != null) {
this.value = val;
this.coder = LATIN1;
return;
}
this(value, off, len);
}

this.coder = UTF16;
this.value = StringUTF16.toBytes(value, off, len);
}
String(byte[] value, byte coder) {
this.value = value;
this.coder = coder;
}

@Deprecated
Expand All @@ -213,32 +195,21 @@ public int length() {
public boolean isEmpty() {
return value.length == 0;
}
@Override
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return this.isLatin1() ? StringLatin1.charAt(this.value, index) : StringUTF16.charAt(this.value, index);
}

native public char charAt(int index);
native public int codePointAt(int index);
native public int codePointBefore(int index);
native public int codePointCount(int beginIndex, int endIndex);
native public int offsetByCodePoints(int index, int codePointOffset);
native public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin);
native void getChars(char dst[], int dstBegin);

@Deprecated
native public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin);
native public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException;
native public byte[] getBytes(String charsetName) throws UnsupportedEncodingException;

public byte[] getBytes(Charset x){
// No Charset model.
if (x == null){
throw new NullPointerException();
}
return StringCoding.encode(x, this.coder, this.value);
if (x == null) throw new NullPointerException();
return StringCoding.encode(x, coder(), value);
}

native public byte[] getBytes();
Expand All @@ -251,6 +222,26 @@ public boolean contentEquals(StringBuffer stringBuffer){
}
}

private boolean nonSyncContentEquals(AbstractStringBuilder abstractStringBuilder) {
int len = length();
if (len != abstractStringBuilder.length()) {
return false;
}
byte v1[] = value;
byte v2[] = abstractStringBuilder.getValue();
if (coder() == abstractStringBuilder.getCoder()) {
int n = v1.length;
for (int i = 0; i < n; i++) {
if (v1[i] != v2[i]) {
return false;
}
}
} else {
return isLatin1() && StringUTF16.contentEquals(v1, v2, len);
}
return true;
}

native static boolean equals0 (char[] a, char[] b, int len);

/**
Expand All @@ -262,21 +253,28 @@ public boolean contentEquals (CharSequence charSequence){
return false;
}

// that should be the common case (String)
if (charSequence.equals(this)){
return true;
// cs is a String
if (charSequence instanceof String) {
return equals(charSequence);
}

// we can do that natively, too
// cs is a StringBuffer, or StringBuilder
if (charSequence instanceof AbstractStringBuilder) {
byte[] val = ((AbstractStringBuilder) charSequence).getValue();
byte coder = ((AbstractStringBuilder) charSequence).getCoder();
assert coder == UTF16 : "Currently only UTF16 is supported for String comparision with an instance of type AbstractStringBuilder";
return StringUTF16.contentEquals(this.value, val, this.length());
if (charSequence instanceof StringBuffer) {
synchronized (charSequence) {
return nonSyncContentEquals((AbstractStringBuilder) charSequence);
}
} else {
return nonSyncContentEquals((AbstractStringBuilder) charSequence);
}
}

// generic CharSequence - expensive
int n = charSequence.length();
if (n != length()) {
return false;
}

byte[] val = this.value;
if (isLatin1()) {
for (int i = 0; i < n; i++) {
Expand Down Expand Up @@ -401,6 +399,10 @@ public static String valueOf(char character) {
native public static String valueOf(double d);
public native String intern();

byte coder() {
return COMPACT_STRINGS ? coder : UTF16;
}

private boolean isLatin1() {
return this.coder == LATIN1;
}
Expand Down

0 comments on commit 1e0702b

Please sign in to comment.