8137326: Methods for comparing CharSequence, StringBuilder, and StringBuffer

Reviewed-by: rriggs, smarks, sherman, tvaleev
This commit is contained in:
Joe Wang 2018-03-01 15:31:04 -08:00
parent 17b8a043c4
commit 5a7aff9897
10 changed files with 651 additions and 13 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2018, 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
@ -88,6 +88,29 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
}
/**
* Compares the objects of two AbstractStringBuilder implementations lexicographically.
*
* @since 11
*/
int compareTo(AbstractStringBuilder another) {
if (this == another) {
return 0;
}
byte val1[] = value;
byte val2[] = another.value;
int count1 = this.count;
int count2 = another.count;
if (coder == another.coder) {
return isLatin1() ? StringLatin1.compareTo(val1, val2, count1, count2)
: StringUTF16.compareTo(val1, val2, count1, count2);
}
return isLatin1() ? StringLatin1.compareToUTF16(val1, val2, count1, count2)
: StringUTF16.compareToLatin1(val1, val2, count1, count2);
}
/**
* Returns the length (character count).
*

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2018, 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
@ -26,6 +26,7 @@
package java.lang;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
@ -43,9 +44,9 @@ import java.util.stream.StreamSupport;
*
* <p> This interface does not refine the general contracts of the {@link
* java.lang.Object#equals(java.lang.Object) equals} and {@link
* java.lang.Object#hashCode() hashCode} methods. The result of comparing two
* objects that implement {@code CharSequence} is therefore, in general,
* undefined. Each object may be implemented by a different class, and there
* java.lang.Object#hashCode() hashCode} methods. The result of testing two objects
* that implement {@code CharSequence} for equality is therefore, in general, undefined.
* Each object may be implemented by a different class, and there
* is no guarantee that each class will be capable of testing its instances
* for equality with those of the other. It is therefore inappropriate to use
* arbitrary {@code CharSequence} instances as elements in a set or as keys in
@ -237,4 +238,54 @@ public interface CharSequence {
Spliterator.ORDERED,
false);
}
/**
* Compares two {@code CharSequence} instances lexicographically. Returns a
* negative value, zero, or a positive value if the first sequence is lexicographically
* less than, equal to, or greater than the second, respectively.
*
* <p>
* The lexicographical ordering of {@code CharSequence} is defined as follows.
* Consider a {@code CharSequence} <i>cs</i> of length <i>len</i> to be a
* sequence of char values, <i>cs[0]</i> to <i>cs[len-1]</i>. Suppose <i>k</i>
* is the lowest index at which the corresponding char values from each sequence
* differ. The lexicographic ordering of the sequences is determined by a numeric
* comparison of the char values <i>cs1[k]</i> with <i>cs2[k]</i>. If there is
* no such index <i>k</i>, the shorter sequence is considered lexicographically
* less than the other. If the sequences have the same length, the sequences are
* considered lexicographically equal.
*
*
* @param cs1 the first {@code CharSequence}
* @param cs2 the second {@code CharSequence}
*
* @return the value {@code 0} if the two {@code CharSequence} are equal;
* a negative integer if the first {@code CharSequence}
* is lexicographically less than the second; or a
* positive integer if the first {@code CharSequence} is
* lexicographically greater than the second.
*
* @since 11
*/
@SuppressWarnings("unchecked")
public static int compare(CharSequence cs1, CharSequence cs2) {
if (Objects.requireNonNull(cs1) == Objects.requireNonNull(cs2)) {
return 0;
}
if (cs1.getClass() == cs2.getClass() && cs1 instanceof Comparable) {
return ((Comparable<Object>) cs1).compareTo(cs2);
}
for (int i = 0, len = Math.min(cs1.length(), cs2.length()); i < len; i++) {
char a = cs1.charAt(i);
char b = cs2.charAt(i);
if (a != b) {
return a - b;
}
}
return cs1.length() - cs2.length();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2018, 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
@ -90,6 +90,14 @@ import jdk.internal.HotSpotIntrinsicCandidate;
* this one, as it supports all of the same operations but it is faster, as
* it performs no synchronization.
*
* @apiNote
* {@code StringBuffer} implements {@code Comparable} but does not override
* {@link Object#equals equals}. Thus, the natural ordering of {@code StringBuffer}
* is inconsistent with equals. Care should be exercised if {@code StringBuffer}
* objects are used as keys in a {@code SortedMap} or elements in a {@code SortedSet}.
* See {@link Comparable}, {@link java.util.SortedMap SortedMap}, or
* {@link java.util.SortedSet SortedSet} for more information.
*
* @author Arthur van Hoff
* @see java.lang.StringBuilder
* @see java.lang.String
@ -97,7 +105,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
*/
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
/**
@ -162,6 +170,35 @@ import jdk.internal.HotSpotIntrinsicCandidate;
append(seq);
}
/**
* Compares two {@code StringBuffer} instances lexicographically. This method
* follows the same rules for lexicographical comparison as defined in the
* {@linkplain java.lang.CharSequence#compare(java.lang.CharSequence,
* java.lang.CharSequence) CharSequence.compare(this, another)} method.
*
* <p>
* For finer-grained, locale-sensitive String comparison, refer to
* {@link java.text.Collator}.
*
* @implNote
* This method synchronizes on {@code this}, the current object, but not
* {@code StringBuffer another} with which {@code this StringBuffer} is compared.
*
* @param another the {@code StringBuffer} to be compared with
*
* @return the value {@code 0} if this {@code StringBuffer} contains the same
* character sequence as that of the argument {@code StringBuffer}; a negative integer
* if this {@code StringBuffer} is lexicographically less than the
* {@code StringBuffer} argument; or a positive integer if this {@code StringBuffer}
* is lexicographically greater than the {@code StringBuffer} argument.
*
* @since 11
*/
@Override
public synchronized int compareTo(StringBuffer another) {
return super.compareTo(another);
}
@Override
public synchronized int length() {
return count;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2018, 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
@ -69,6 +69,14 @@ import jdk.internal.HotSpotIntrinsicCandidate;
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
* @apiNote
* {@code StringBuilder} implements {@code Comparable} but does not override
* {@link Object#equals equals}. Thus, the natural ordering of {@code StringBuilder}
* is inconsistent with equals. Care should be exercised if {@code StringBuilder}
* objects are used as keys in a {@code SortedMap} or elements in a {@code SortedSet}.
* See {@link Comparable}, {@link java.util.SortedMap SortedMap}, or
* {@link java.util.SortedSet SortedSet} for more information.
*
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
@ -76,7 +84,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
*/
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
/** use serialVersionUID for interoperability */
@ -130,6 +138,31 @@ public final class StringBuilder
append(seq);
}
/**
* Compares two {@code StringBuilder} instances lexicographically. This method
* follows the same rules for lexicographical comparison as defined in the
* {@linkplain java.lang.CharSequence#compare(java.lang.CharSequence,
* java.lang.CharSequence) CharSequence.compare(this, another)} method.
*
* <p>
* For finer-grained, locale-sensitive String comparison, refer to
* {@link java.text.Collator}.
*
* @param another the {@code StringBuilder} to be compared with
*
* @return the value {@code 0} if this {@code StringBuilder} contains the same
* character sequence as that of the argument {@code StringBuilder}; a negative integer
* if this {@code StringBuilder} is lexicographically less than the
* {@code StringBuilder} argument; or a positive integer if this {@code StringBuilder}
* is lexicographically greater than the {@code StringBuilder} argument.
*
* @since 11
*/
@Override
public int compareTo(StringBuilder another) {
return super.compareTo(another);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
@ -103,6 +103,10 @@ final class StringLatin1 {
public static int compareTo(byte[] value, byte[] other) {
int len1 = value.length;
int len2 = other.length;
return compareTo(value, other, len1, len2);
}
public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
if (value[k] != other[k]) {
@ -116,6 +120,20 @@ final class StringLatin1 {
public static int compareToUTF16(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = StringUTF16.length(other);
return compareToUTF16Values(value, other, len1, len2);
}
/*
* Checks the boundary and then compares the byte arrays.
*/
public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) {
checkOffset(len1, length(value));
checkOffset(len2, StringUTF16.length(other));
return compareToUTF16Values(value, other, len1, len2);
}
private static int compareToUTF16Values(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
@ -273,6 +273,20 @@ final class StringUTF16 {
public static int compareTo(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = length(other);
return compareValues(value, other, len1, len2);
}
/*
* Checks the boundary and then compares the byte arrays.
*/
public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
checkOffset(len1, value);
checkOffset(len2, other);
return compareValues(value, other, len1, len2);
}
private static int compareValues(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
@ -289,6 +303,10 @@ final class StringUTF16 {
return -StringLatin1.compareToUTF16(other, value);
}
public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) {
return -StringLatin1.compareToUTF16(other, value, len2, len1);
}
public static int compareToCI(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = length(other);