/* * Decompiled with CFR 0.152. */ package com.google.common.base; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Platform; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.SmallCharMatcher; import java.util.Arrays; import java.util.BitSet; import javax.annotation.CheckReturnValue; @Beta @GwtCompatible(emulated=true) public abstract class CharMatcher implements Predicate { public static final CharMatcher BREAKING_WHITESPACE = new CharMatcher(){ @Override public boolean matches(char c) { switch (c) { case '\t': case '\n': case '\u000b': case '\f': case '\r': case ' ': case '\u0085': case '\u1680': case '\u2028': case '\u2029': case '\u205f': case '\u3000': { return true; } case '\u2007': { return false; } } return c >= '\u2000' && c <= '\u200a'; } @Override public String toString() { return "CharMatcher.BREAKING_WHITESPACE"; } }; public static final CharMatcher ASCII = CharMatcher.inRange('\u0000', '\u007f', "CharMatcher.ASCII"); private static final String ZEROES = "0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1b50\u1bb0\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10"; private static final String NINES; public static final CharMatcher DIGIT; public static final CharMatcher JAVA_DIGIT; public static final CharMatcher JAVA_LETTER; public static final CharMatcher JAVA_LETTER_OR_DIGIT; public static final CharMatcher JAVA_UPPER_CASE; public static final CharMatcher JAVA_LOWER_CASE; public static final CharMatcher JAVA_ISO_CONTROL; public static final CharMatcher INVISIBLE; public static final CharMatcher SINGLE_WIDTH; public static final CharMatcher ANY; public static final CharMatcher NONE; final String description; private static final int DISTINCT_CHARS = 65536; static final String WHITESPACE_TABLE = "\u2002\u3000\r\u0085\u200a\u2005\u2000\u3000\u2029\u000b\u3000\u2008\u2003\u205f\u3000\u1680\t \u2006\u2001\u202f\u00a0\f\u2009\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000"; static final int WHITESPACE_MULTIPLIER = 1682554634; static final int WHITESPACE_SHIFT; public static final CharMatcher WHITESPACE; private static String showCharacter(char c) { String hex = "0123456789ABCDEF"; char[] tmp = new char[]{'\\', 'u', '\u0000', '\u0000', '\u0000', '\u0000'}; for (int i = 0; i < 4; ++i) { tmp[5 - i] = hex.charAt(c & 0xF); c = (char)(c >> 4); } return String.copyValueOf(tmp); } public static CharMatcher is(final char match) { String string = String.valueOf(String.valueOf(CharMatcher.showCharacter(match))); String description = new StringBuilder(18 + string.length()).append("CharMatcher.is('").append(string).append("')").toString(); return new FastMatcher(description){ @Override public boolean matches(char c) { return c == match; } @Override public String replaceFrom(CharSequence sequence, char replacement) { return sequence.toString().replace(match, replacement); } @Override public CharMatcher and(CharMatcher other) { return other.matches(match) ? this : NONE; } @Override public CharMatcher or(CharMatcher other) { return other.matches(match) ? other : super.or(other); } @Override public CharMatcher negate() { return 9.isNot(match); } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { table.set(match); } }; } public static CharMatcher isNot(final char match) { String string = String.valueOf(String.valueOf(CharMatcher.showCharacter(match))); String description = new StringBuilder(21 + string.length()).append("CharMatcher.isNot('").append(string).append("')").toString(); return new FastMatcher(description){ @Override public boolean matches(char c) { return c != match; } @Override public CharMatcher and(CharMatcher other) { return other.matches(match) ? super.and(other) : other; } @Override public CharMatcher or(CharMatcher other) { return other.matches(match) ? ANY : this; } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { table.set(0, match); table.set(match + '\u0001', 65536); } @Override public CharMatcher negate() { return 10.is(match); } }; } public static CharMatcher anyOf(CharSequence sequence) { switch (sequence.length()) { case 0: { return NONE; } case 1: { return CharMatcher.is(sequence.charAt(0)); } case 2: { return CharMatcher.isEither(sequence.charAt(0), sequence.charAt(1)); } } final char[] chars = sequence.toString().toCharArray(); Arrays.sort(chars); StringBuilder description = new StringBuilder("CharMatcher.anyOf(\""); for (char c : chars) { description.append(CharMatcher.showCharacter(c)); } description.append("\")"); return new CharMatcher(description.toString()){ @Override public boolean matches(char c) { return Arrays.binarySearch(chars, c) >= 0; } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { for (char c : chars) { table.set(c); } } }; } private static CharMatcher isEither(final char match1, final char match2) { String string = String.valueOf(String.valueOf(CharMatcher.showCharacter(match1))); String string2 = String.valueOf(String.valueOf(CharMatcher.showCharacter(match2))); String description = new StringBuilder(21 + string.length() + string2.length()).append("CharMatcher.anyOf(\"").append(string).append(string2).append("\")").toString(); return new FastMatcher(description){ @Override public boolean matches(char c) { return c == match1 || c == match2; } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { table.set(match1); table.set(match2); } }; } public static CharMatcher noneOf(CharSequence sequence) { return CharMatcher.anyOf(sequence).negate(); } public static CharMatcher inRange(char startInclusive, char endInclusive) { Preconditions.checkArgument(endInclusive >= startInclusive); String string = String.valueOf(String.valueOf(CharMatcher.showCharacter(startInclusive))); String string2 = String.valueOf(String.valueOf(CharMatcher.showCharacter(endInclusive))); String description = new StringBuilder(27 + string.length() + string2.length()).append("CharMatcher.inRange('").append(string).append("', '").append(string2).append("')").toString(); return CharMatcher.inRange(startInclusive, endInclusive, description); } static CharMatcher inRange(final char startInclusive, final char endInclusive, String description) { return new FastMatcher(description){ @Override public boolean matches(char c) { return startInclusive <= c && c <= endInclusive; } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { table.set((int)startInclusive, endInclusive + '\u0001'); } }; } public static CharMatcher forPredicate(final Predicate predicate) { Preconditions.checkNotNull(predicate); if (predicate instanceof CharMatcher) { return (CharMatcher)predicate; } String string = String.valueOf(String.valueOf(predicate)); String description = new StringBuilder(26 + string.length()).append("CharMatcher.forPredicate(").append(string).append(")").toString(); return new CharMatcher(description){ @Override public boolean matches(char c) { return predicate.apply(Character.valueOf(c)); } @Override public boolean apply(Character character) { return predicate.apply(Preconditions.checkNotNull(character)); } }; } CharMatcher(String description) { this.description = description; } protected CharMatcher() { this.description = super.toString(); } public abstract boolean matches(char var1); public CharMatcher negate() { return new NegatedMatcher(this); } public CharMatcher and(CharMatcher other) { return new And(this, Preconditions.checkNotNull(other)); } public CharMatcher or(CharMatcher other) { return new Or(this, Preconditions.checkNotNull(other)); } public CharMatcher precomputed() { return Platform.precomputeCharMatcher(this); } CharMatcher withToString(String description) { throw new UnsupportedOperationException(); } @GwtIncompatible(value="java.util.BitSet") CharMatcher precomputedInternal() { String string; BitSet table = new BitSet(); this.setBits(table); int totalCharacters = table.cardinality(); if (totalCharacters * 2 <= 65536) { return CharMatcher.precomputedPositive(totalCharacters, table, this.description); } table.flip(0, 65536); int negatedCharacters = 65536 - totalCharacters; String suffix = ".negate()"; if (this.description.endsWith(suffix)) { string = this.description.substring(0, this.description.length() - suffix.length()); } else { String string2 = String.valueOf(this.description); String string3 = String.valueOf(suffix); string = string3.length() != 0 ? string2.concat(string3) : new String(string2); } String negatedDescription = string; return new NegatedFastMatcher(this.toString(), CharMatcher.precomputedPositive(negatedCharacters, table, negatedDescription)); } @GwtIncompatible(value="java.util.BitSet") private static CharMatcher precomputedPositive(int totalCharacters, BitSet table, String description) { switch (totalCharacters) { case 0: { return NONE; } case 1: { return CharMatcher.is((char)table.nextSetBit(0)); } case 2: { char c1 = (char)table.nextSetBit(0); char c2 = (char)table.nextSetBit(c1 + '\u0001'); return CharMatcher.isEither(c1, c2); } } return CharMatcher.isSmall(totalCharacters, table.length()) ? SmallCharMatcher.from(table, description) : new BitSetMatcher(table, description); } @GwtIncompatible(value="SmallCharMatcher") private static boolean isSmall(int totalCharacters, int tableLength) { return totalCharacters <= 1023 && tableLength > totalCharacters * 4 * 16; } @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { for (int c = 65535; c >= 0; --c) { if (!this.matches((char)c)) continue; table.set(c); } } public boolean matchesAnyOf(CharSequence sequence) { return !this.matchesNoneOf(sequence); } public boolean matchesAllOf(CharSequence sequence) { for (int i = sequence.length() - 1; i >= 0; --i) { if (this.matches(sequence.charAt(i))) continue; return false; } return true; } public boolean matchesNoneOf(CharSequence sequence) { return this.indexIn(sequence) == -1; } public int indexIn(CharSequence sequence) { int length = sequence.length(); for (int i = 0; i < length; ++i) { if (!this.matches(sequence.charAt(i))) continue; return i; } return -1; } public int indexIn(CharSequence sequence, int start) { int length = sequence.length(); Preconditions.checkPositionIndex(start, length); for (int i = start; i < length; ++i) { if (!this.matches(sequence.charAt(i))) continue; return i; } return -1; } public int lastIndexIn(CharSequence sequence) { for (int i = sequence.length() - 1; i >= 0; --i) { if (!this.matches(sequence.charAt(i))) continue; return i; } return -1; } public int countIn(CharSequence sequence) { int count = 0; for (int i = 0; i < sequence.length(); ++i) { if (!this.matches(sequence.charAt(i))) continue; ++count; } return count; } @CheckReturnValue public String removeFrom(CharSequence sequence) { String string = sequence.toString(); int pos = this.indexIn(string); if (pos == -1) { return string; } char[] chars = string.toCharArray(); int spread = 1; block0: while (true) { ++pos; while (pos != chars.length) { if (!this.matches(chars[pos])) { chars[pos - spread] = chars[pos]; ++pos; continue; } ++spread; continue block0; } break; } return new String(chars, 0, pos - spread); } @CheckReturnValue public String retainFrom(CharSequence sequence) { return this.negate().removeFrom(sequence); } @CheckReturnValue public String replaceFrom(CharSequence sequence, char replacement) { String string = sequence.toString(); int pos = this.indexIn(string); if (pos == -1) { return string; } char[] chars = string.toCharArray(); chars[pos] = replacement; for (int i = pos + 1; i < chars.length; ++i) { if (!this.matches(chars[i])) continue; chars[i] = replacement; } return new String(chars); } @CheckReturnValue public String replaceFrom(CharSequence sequence, CharSequence replacement) { int replacementLen = replacement.length(); if (replacementLen == 0) { return this.removeFrom(sequence); } if (replacementLen == 1) { return this.replaceFrom(sequence, replacement.charAt(0)); } String string = sequence.toString(); int pos = this.indexIn(string); if (pos == -1) { return string; } int len = string.length(); StringBuilder buf = new StringBuilder(len * 3 / 2 + 16); int oldpos = 0; do { buf.append(string, oldpos, pos); buf.append(replacement); } while ((pos = this.indexIn(string, oldpos = pos + 1)) != -1); buf.append(string, oldpos, len); return buf.toString(); } @CheckReturnValue public String trimFrom(CharSequence sequence) { int last; int first; int len = sequence.length(); for (first = 0; first < len && this.matches(sequence.charAt(first)); ++first) { } for (last = len - 1; last > first && this.matches(sequence.charAt(last)); --last) { } return sequence.subSequence(first, last + 1).toString(); } @CheckReturnValue public String trimLeadingFrom(CharSequence sequence) { int len = sequence.length(); for (int first = 0; first < len; ++first) { if (this.matches(sequence.charAt(first))) continue; return sequence.subSequence(first, len).toString(); } return ""; } @CheckReturnValue public String trimTrailingFrom(CharSequence sequence) { int len = sequence.length(); for (int last = len - 1; last >= 0; --last) { if (this.matches(sequence.charAt(last))) continue; return sequence.subSequence(0, last + 1).toString(); } return ""; } @CheckReturnValue public String collapseFrom(CharSequence sequence, char replacement) { int len = sequence.length(); for (int i = 0; i < len; ++i) { char c = sequence.charAt(i); if (!this.matches(c)) continue; if (!(c != replacement || i != len - 1 && this.matches(sequence.charAt(i + 1)))) { ++i; continue; } StringBuilder builder = new StringBuilder(len).append(sequence.subSequence(0, i)).append(replacement); return this.finishCollapseFrom(sequence, i + 1, len, replacement, builder, true); } return sequence.toString(); } @CheckReturnValue public String trimAndCollapseFrom(CharSequence sequence, char replacement) { int last; int first; int len = sequence.length(); for (first = 0; first < len && this.matches(sequence.charAt(first)); ++first) { } for (last = len - 1; last > first && this.matches(sequence.charAt(last)); --last) { } return first == 0 && last == len - 1 ? this.collapseFrom(sequence, replacement) : this.finishCollapseFrom(sequence, first, last + 1, replacement, new StringBuilder(last + 1 - first), false); } private String finishCollapseFrom(CharSequence sequence, int start, int end, char replacement, StringBuilder builder, boolean inMatchingGroup) { for (int i = start; i < end; ++i) { char c = sequence.charAt(i); if (this.matches(c)) { if (inMatchingGroup) continue; builder.append(replacement); inMatchingGroup = true; continue; } builder.append(c); inMatchingGroup = false; } return builder.toString(); } @Override @Deprecated public boolean apply(Character character) { return this.matches(character.charValue()); } public String toString() { return this.description; } static { StringBuilder builder = new StringBuilder(ZEROES.length()); for (int i = 0; i < ZEROES.length(); ++i) { builder.append((char)(ZEROES.charAt(i) + 9)); } NINES = builder.toString(); DIGIT = new RangesMatcher("CharMatcher.DIGIT", ZEROES.toCharArray(), NINES.toCharArray()); JAVA_DIGIT = new CharMatcher("CharMatcher.JAVA_DIGIT"){ @Override public boolean matches(char c) { return Character.isDigit(c); } }; JAVA_LETTER = new CharMatcher("CharMatcher.JAVA_LETTER"){ @Override public boolean matches(char c) { return Character.isLetter(c); } }; JAVA_LETTER_OR_DIGIT = new CharMatcher("CharMatcher.JAVA_LETTER_OR_DIGIT"){ @Override public boolean matches(char c) { return Character.isLetterOrDigit(c); } }; JAVA_UPPER_CASE = new CharMatcher("CharMatcher.JAVA_UPPER_CASE"){ @Override public boolean matches(char c) { return Character.isUpperCase(c); } }; JAVA_LOWER_CASE = new CharMatcher("CharMatcher.JAVA_LOWER_CASE"){ @Override public boolean matches(char c) { return Character.isLowerCase(c); } }; JAVA_ISO_CONTROL = CharMatcher.inRange('\u0000', '\u001f').or(CharMatcher.inRange('\u007f', '\u009f')).withToString("CharMatcher.JAVA_ISO_CONTROL"); INVISIBLE = new RangesMatcher("CharMatcher.INVISIBLE", "\u0000\u007f\u00ad\u0600\u061c\u06dd\u070f\u1680\u180e\u2000\u2028\u205f\u2066\u2067\u2068\u2069\u206a\u3000\ud800\ufeff\ufff9\ufffa".toCharArray(), " \u00a0\u00ad\u0604\u061c\u06dd\u070f\u1680\u180e\u200f\u202f\u2064\u2066\u2067\u2068\u2069\u206f\u3000\uf8ff\ufeff\ufff9\ufffb".toCharArray()); SINGLE_WIDTH = new RangesMatcher("CharMatcher.SINGLE_WIDTH", "\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(), "\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray()); ANY = new FastMatcher("CharMatcher.ANY"){ @Override public boolean matches(char c) { return true; } @Override public int indexIn(CharSequence sequence) { return sequence.length() == 0 ? -1 : 0; } @Override public int indexIn(CharSequence sequence, int start) { int length = sequence.length(); Preconditions.checkPositionIndex(start, length); return start == length ? -1 : start; } @Override public int lastIndexIn(CharSequence sequence) { return sequence.length() - 1; } @Override public boolean matchesAllOf(CharSequence sequence) { Preconditions.checkNotNull(sequence); return true; } @Override public boolean matchesNoneOf(CharSequence sequence) { return sequence.length() == 0; } @Override public String removeFrom(CharSequence sequence) { Preconditions.checkNotNull(sequence); return ""; } @Override public String replaceFrom(CharSequence sequence, char replacement) { char[] array = new char[sequence.length()]; Arrays.fill(array, replacement); return new String(array); } @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) { StringBuilder retval = new StringBuilder(sequence.length() * replacement.length()); for (int i = 0; i < sequence.length(); ++i) { retval.append(replacement); } return retval.toString(); } @Override public String collapseFrom(CharSequence sequence, char replacement) { return sequence.length() == 0 ? "" : String.valueOf(replacement); } @Override public String trimFrom(CharSequence sequence) { Preconditions.checkNotNull(sequence); return ""; } @Override public int countIn(CharSequence sequence) { return sequence.length(); } @Override public CharMatcher and(CharMatcher other) { return Preconditions.checkNotNull(other); } @Override public CharMatcher or(CharMatcher other) { Preconditions.checkNotNull(other); return this; } @Override public CharMatcher negate() { return NONE; } }; NONE = new FastMatcher("CharMatcher.NONE"){ @Override public boolean matches(char c) { return false; } @Override public int indexIn(CharSequence sequence) { Preconditions.checkNotNull(sequence); return -1; } @Override public int indexIn(CharSequence sequence, int start) { int length = sequence.length(); Preconditions.checkPositionIndex(start, length); return -1; } @Override public int lastIndexIn(CharSequence sequence) { Preconditions.checkNotNull(sequence); return -1; } @Override public boolean matchesAllOf(CharSequence sequence) { return sequence.length() == 0; } @Override public boolean matchesNoneOf(CharSequence sequence) { Preconditions.checkNotNull(sequence); return true; } @Override public String removeFrom(CharSequence sequence) { return sequence.toString(); } @Override public String replaceFrom(CharSequence sequence, char replacement) { return sequence.toString(); } @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) { Preconditions.checkNotNull(replacement); return sequence.toString(); } @Override public String collapseFrom(CharSequence sequence, char replacement) { return sequence.toString(); } @Override public String trimFrom(CharSequence sequence) { return sequence.toString(); } @Override public String trimLeadingFrom(CharSequence sequence) { return sequence.toString(); } @Override public String trimTrailingFrom(CharSequence sequence) { return sequence.toString(); } @Override public int countIn(CharSequence sequence) { Preconditions.checkNotNull(sequence); return 0; } @Override public CharMatcher and(CharMatcher other) { Preconditions.checkNotNull(other); return this; } @Override public CharMatcher or(CharMatcher other) { return Preconditions.checkNotNull(other); } @Override public CharMatcher negate() { return ANY; } }; WHITESPACE_SHIFT = Integer.numberOfLeadingZeros(WHITESPACE_TABLE.length() - 1); WHITESPACE = new FastMatcher("WHITESPACE"){ @Override public boolean matches(char c) { return CharMatcher.WHITESPACE_TABLE.charAt(1682554634 * c >>> WHITESPACE_SHIFT) == c; } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { for (int i = 0; i < CharMatcher.WHITESPACE_TABLE.length(); ++i) { table.set(CharMatcher.WHITESPACE_TABLE.charAt(i)); } } }; } @GwtIncompatible(value="java.util.BitSet") private static class BitSetMatcher extends FastMatcher { private final BitSet table; private BitSetMatcher(BitSet table, String description) { super(description); if (table.length() + 64 < table.size()) { table = (BitSet)table.clone(); } this.table = table; } @Override public boolean matches(char c) { return this.table.get(c); } @Override void setBits(BitSet bitSet) { bitSet.or(this.table); } } static final class NegatedFastMatcher extends NegatedMatcher { NegatedFastMatcher(CharMatcher original) { super(original); } NegatedFastMatcher(String toString, CharMatcher original) { super(toString, original); } @Override public final CharMatcher precomputed() { return this; } @Override CharMatcher withToString(String description) { return new NegatedFastMatcher(description, this.original); } } static abstract class FastMatcher extends CharMatcher { FastMatcher() { } FastMatcher(String description) { super(description); } @Override public final CharMatcher precomputed() { return this; } @Override public CharMatcher negate() { return new NegatedFastMatcher(this); } } private static class Or extends CharMatcher { final CharMatcher first; final CharMatcher second; Or(CharMatcher a, CharMatcher b, String description) { super(description); this.first = Preconditions.checkNotNull(a); this.second = Preconditions.checkNotNull(b); } Or(CharMatcher a, CharMatcher b) { String string = String.valueOf(String.valueOf(a)); String string2 = String.valueOf(String.valueOf(b)); this(a, b, new StringBuilder(18 + string.length() + string2.length()).append("CharMatcher.or(").append(string).append(", ").append(string2).append(")").toString()); } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { this.first.setBits(table); this.second.setBits(table); } @Override public boolean matches(char c) { return this.first.matches(c) || this.second.matches(c); } @Override CharMatcher withToString(String description) { return new Or(this.first, this.second, description); } } private static class And extends CharMatcher { final CharMatcher first; final CharMatcher second; And(CharMatcher a, CharMatcher b) { String string = String.valueOf(String.valueOf(a)); String string2 = String.valueOf(String.valueOf(b)); this(a, b, new StringBuilder(19 + string.length() + string2.length()).append("CharMatcher.and(").append(string).append(", ").append(string2).append(")").toString()); } And(CharMatcher a, CharMatcher b, String description) { super(description); this.first = Preconditions.checkNotNull(a); this.second = Preconditions.checkNotNull(b); } @Override public boolean matches(char c) { return this.first.matches(c) && this.second.matches(c); } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { BitSet tmp1 = new BitSet(); this.first.setBits(tmp1); BitSet tmp2 = new BitSet(); this.second.setBits(tmp2); tmp1.and(tmp2); table.or(tmp1); } @Override CharMatcher withToString(String description) { return new And(this.first, this.second, description); } } private static class NegatedMatcher extends CharMatcher { final CharMatcher original; NegatedMatcher(String toString, CharMatcher original) { super(toString); this.original = original; } NegatedMatcher(CharMatcher original) { String string = String.valueOf(String.valueOf(original)); this(new StringBuilder(9 + string.length()).append(string).append(".negate()").toString(), original); } @Override public boolean matches(char c) { return !this.original.matches(c); } @Override public boolean matchesAllOf(CharSequence sequence) { return this.original.matchesNoneOf(sequence); } @Override public boolean matchesNoneOf(CharSequence sequence) { return this.original.matchesAllOf(sequence); } @Override public int countIn(CharSequence sequence) { return sequence.length() - this.original.countIn(sequence); } @Override @GwtIncompatible(value="java.util.BitSet") void setBits(BitSet table) { BitSet tmp = new BitSet(); this.original.setBits(tmp); tmp.flip(0, 65536); table.or(tmp); } @Override public CharMatcher negate() { return this.original; } @Override CharMatcher withToString(String description) { return new NegatedMatcher(description, this.original); } } private static class RangesMatcher extends CharMatcher { private final char[] rangeStarts; private final char[] rangeEnds; RangesMatcher(String description, char[] rangeStarts, char[] rangeEnds) { super(description); this.rangeStarts = rangeStarts; this.rangeEnds = rangeEnds; Preconditions.checkArgument(rangeStarts.length == rangeEnds.length); for (int i = 0; i < rangeStarts.length; ++i) { Preconditions.checkArgument(rangeStarts[i] <= rangeEnds[i]); if (i + 1 >= rangeStarts.length) continue; Preconditions.checkArgument(rangeEnds[i] < rangeStarts[i + 1]); } } @Override public boolean matches(char c) { int index = Arrays.binarySearch(this.rangeStarts, c); if (index >= 0) { return true; } return (index = ~index - 1) >= 0 && c <= this.rangeEnds[index]; } } }