Repository: netty/netty
File: common/src/main/java/io/netty/util/AsciiString.java (Java)

Code before:
        return regionMatches(length() - suffixLen, suffix, 0, suffixLen);
    }

    /**
     * Compares the specified string to this string ignoring the case of the characters and returns true if they are
     * equal.
     *
     * @param string the string to compare.
     * @return {@code true} if the specified string is equal to this string, {@code false} otherwise.
     */
    public boolean contentEqualsIgnoreCase(CharSequence string) {
        if (this == string) {
            return true;
        }

        if (string == null || string.length() != length()) {
            return false;
        }

        byte[] value = this.value;
        if (string instanceof AsciiString) {
            AsciiString rhs = (AsciiString) string;
            byte[] rhsValue = rhs.value;
            if ((arrayOffset() | rhs.arrayOffset()) == 0) {
                for (int i = 0; i < length; ++i) {
                    if (!equalsIgnoreCase(value[i], rhsValue[i])) {
                        return false;
                    }
                }
                return true;
            }
            return misalignedEqualsIgnoreCase(rhs, value, rhsValue);
        }

        for (int i = arrayOffset(), j = 0, end = length(); j < end; ++i, ++j) {
            if (!equalsIgnoreCase(b2c(value[i]), string.charAt(j))) {
                return false;
            }
        }
        return true;
    }

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


Review comment (performance):
Let me extract it into a thread:

> And I think it could be made even faster by using AsciiString::cache to perform a quick isLowerCase on the cached AsciiString saving a byte to know if is a full lowercase String aready (which is the most common use case for cached ones).
This will enable super quick equality checks for known HTTP 1.1 lower-case header names and faster ones for cases like the one used in the benchmark (eg Accept vs accept). wdyt @normanmaurer @idelpivnitskiy ?


This sounds like an interesting idea, but possible for another PR, bcz adding a knowledge of "all lower case" or "all upper case" may help to improve a few other methods.

I also wonder if we need to implement a real internal cache (with `ConcurrentHashMap`?) for `AsciiString::cached` method to always return the same `AsciiString` instance when users try to create an `AsciiString` equivalent for exact same `String`. wdyt?

Code after:
        return regionMatches(length() - suffixLen, suffix, 0, suffixLen);
    }

    /**
     * Compares the specified string to this string ignoring the case of the characters and returns true if they are
     * equal.
     *
     * @param string the string to compare.
     * @return {@code true} if the specified string is equal to this string, {@code false} otherwise.
     */
    public boolean contentEqualsIgnoreCase(CharSequence string) {
        if (this == string) {
            return true;
        }

        if (string == null || string.length() != length()) {
            return false;
        }

        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);
        }

        byte[] value = this.value;
        for (int i = offset, j = 0; j < string.length(); ++i, ++j) {
            if (!equalsIgnoreCase(b2c(value[i]), string.charAt(j))) {
                return false;
            }
        }
        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;
            }
        }