Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT]Enhance Performance of AsciiString Methods #13534

Draft
wants to merge 24 commits into
base: 4.1
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 5 additions & 19 deletions buffer/src/main/java/io/netty/buffer/ByteBufUtil.java
Expand Up @@ -27,6 +27,7 @@
import io.netty.util.internal.ObjectPool.Handle;
import io.netty.util.internal.ObjectPool.ObjectCreator;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SWARUtil;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
Expand Down Expand Up @@ -514,21 +515,6 @@ private static long uintFromLE(long value) {
return Long.reverseBytes(value) >>> Integer.SIZE;
}

private static final class SWARByteSearch {

private static long compilePattern(byte byteToFind) {
return (byteToFind & 0xFFL) * 0x101010101010101L;
}

private static int firstAnyPattern(long word, long pattern, boolean leading) {
long input = word ^ pattern;
long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;
tmp = ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);
final int binaryPosition = leading? Long.numberOfLeadingZeros(tmp) : Long.numberOfTrailingZeros(tmp);
return binaryPosition >>> 3;
}
}

private static int unrolledFirstIndexOf(AbstractByteBuf buffer, int fromIndex, int byteCount, byte value) {
assert byteCount > 0 && byteCount < 8;
if (buffer._getByte(fromIndex) == value) {
Expand Down Expand Up @@ -604,13 +590,13 @@ static int firstIndexOf(AbstractByteBuf buffer, int fromIndex, int toIndex, byte
final ByteOrder nativeOrder = ByteOrder.nativeOrder();
final boolean isNative = nativeOrder == buffer.order();
final boolean useLE = nativeOrder == ByteOrder.LITTLE_ENDIAN;
final long pattern = SWARByteSearch.compilePattern(value);
final long pattern = SWARUtil.compilePattern(value);
for (int i = 0; i < longCount; i++) {
// use the faster available getLong
final long word = useLE? buffer._getLongLE(offset) : buffer._getLong(offset);
int index = SWARByteSearch.firstAnyPattern(word, pattern, isNative);
if (index < Long.BYTES) {
return offset + index;
final long mask = SWARUtil.applyPattern(word, pattern);
if (mask != 0) {
return offset + SWARUtil.getIndex(mask, isNative);
}
offset += Long.BYTES;
}
Expand Down
99 changes: 16 additions & 83 deletions common/src/main/java/io/netty/util/AsciiString.java
Expand Up @@ -534,18 +534,8 @@ public boolean contentEqualsIgnoreCase(CharSequence string) {
}

if (string instanceof AsciiString) {
AsciiString other = (AsciiString) string;
byte[] value = this.value;
if (offset == 0 && other.offset == 0 && length == value.length) {
byte[] otherValue = other.value;
for (int i = 0; i < value.length; ++i) {
if (!equalsIgnoreCase(value[i], otherValue[i])) {
return false;
}
}
return true;
}
return misalignedEqualsIgnoreCase(other);
AsciiString rhs = (AsciiString) string;
return AsciiStringUtil.equalsIgnoreCases(value, offset, rhs.value, rhs.offset, length);
}

byte[] value = this.value;
Expand All @@ -557,17 +547,6 @@ public boolean contentEqualsIgnoreCase(CharSequence string) {
return true;
}

private boolean misalignedEqualsIgnoreCase(AsciiString other) {
byte[] value = this.value;
byte[] otherValue = other.value;
for (int i = offset, j = other.offset, end = offset + length; i < end; ++i, ++j) {
if (!equalsIgnoreCase(value[i], otherValue[j])) {
return false;
}
}
return true;
}

/**
* Copies the characters in this string to a character array.
*
Expand Down Expand Up @@ -744,13 +723,14 @@ public int indexOf(char ch, int start) {
}

final byte chAsByte = c2b0(ch);
final int len = offset + length;
for (int i = start + offset; i < len; ++i) {
if (value[i] == chAsByte) {
return i - offset;
}
final int offset = this.offset;
final int fromIndex = start + offset;
final int toIndex = offset + length;
final int index = AsciiStringUtil.firstIndexOf(value, fromIndex, toIndex, chAsByte);
if (index < 0) {
return INDEX_NOT_FOUND;
}
return INDEX_NOT_FOUND;
return index - offset;
}

/**
Expand Down Expand Up @@ -941,27 +921,12 @@ public boolean startsWith(CharSequence prefix, int start) {
* @return a new string containing the lowercase characters equivalent to the characters in this string.
*/
public AsciiString toLowerCase() {
boolean lowercased = true;
int i, j;
final int len = length() + arrayOffset();
for (i = arrayOffset(); i < len; ++i) {
byte b = value[i];
if (b >= 'A' && b <= 'Z') {
lowercased = false;
break;
}
}

// Check if this string does not contain any uppercase characters.
if (lowercased) {
if (!AsciiStringUtil.containsUpperCase(value, offset, length)) {
return this;
}

final byte[] newValue = PlatformDependent.allocateUninitializedArray(length());
for (i = 0, j = arrayOffset(); i < newValue.length; ++i, ++j) {
newValue[i] = toLowerCase(value[j]);
}

final byte[] newValue = PlatformDependent.allocateUninitializedArray(length);
AsciiStringUtil.toLowerCase(value, offset, newValue, 0, length);
return new AsciiString(newValue, false);
}

Expand All @@ -971,27 +936,11 @@ public AsciiString toLowerCase() {
* @return a new string containing the uppercase characters equivalent to the characters in this string.
*/
public AsciiString toUpperCase() {
boolean uppercased = true;
int i, j;
final int len = length() + arrayOffset();
for (i = arrayOffset(); i < len; ++i) {
byte b = value[i];
if (b >= 'a' && b <= 'z') {
uppercased = false;
break;
}
}

// Check if this string does not contain any lowercase characters.
if (uppercased) {
if (!AsciiStringUtil.containsLowerCase(value, offset, length)) {
return this;
}

final byte[] newValue = PlatformDependent.allocateUninitializedArray(length());
for (i = 0, j = arrayOffset(); i < newValue.length; ++i, ++j) {
newValue[i] = toUpperCase(value[j]);
}

final byte[] newValue = PlatformDependent.allocateUninitializedArray(length);
AsciiStringUtil.toUpperCase(value, offset, newValue, 0, length);
return new AsciiString(newValue, false);
}

Expand Down Expand Up @@ -1834,18 +1783,10 @@ public static int indexOf(final CharSequence cs, final char searchChar, int star
return INDEX_NOT_FOUND;
}

private static boolean equalsIgnoreCase(byte a, byte b) {
return a == b || toLowerCase(a) == toLowerCase(b);
}

private static boolean equalsIgnoreCase(char a, char b) {
return a == b || toLowerCase(a) == toLowerCase(b);
}

private static byte toLowerCase(byte b) {
return isUpperCase(b) ? (byte) (b + 32) : b;
}

/**
* If the character is uppercase - converts the character to lowercase,
* otherwise returns the character as it is. Only for ASCII characters.
Expand All @@ -1856,16 +1797,8 @@ public static char toLowerCase(char c) {
return isUpperCase(c) ? (char) (c + 32) : c;
}

private static byte toUpperCase(byte b) {
return isLowerCase(b) ? (byte) (b - 32) : b;
}

private static boolean isLowerCase(byte value) {
return value >= 'a' && value <= 'z';
}

public static boolean isUpperCase(byte value) {
return value >= 'A' && value <= 'Z';
return AsciiStringUtil.isUpperCase(value);
}

public static boolean isUpperCase(char value) {
Expand Down