protected void mergeRanges(Token token) { RangeToken tok = (RangeToken) token; this.sortRanges(); tok.sortRanges(); if (tok.ranges == null) return; this.icaseCache = null; this.setSorted(true); if (this.ranges == null) { this.ranges = new int[tok.ranges.length]; System.arraycopy(tok.ranges, 0, this.ranges, 0, tok.ranges.length); return; } int[] result = new int[this.ranges.length + tok.ranges.length]; for (int i = 0, j = 0, k = 0; i < this.ranges.length || j < tok.ranges.length; ) { if (i >= this.ranges.length) { result[k++] = tok.ranges[j++]; result[k++] = tok.ranges[j++]; } else if (j >= tok.ranges.length) { result[k++] = this.ranges[i++]; result[k++] = this.ranges[i++]; } else if (tok.ranges[j] < this.ranges[i] || tok.ranges[j] == this.ranges[i] && tok.ranges[j + 1] < this.ranges[i + 1]) { result[k++] = tok.ranges[j++]; result[k++] = tok.ranges[j++]; } else { result[k++] = this.ranges[i++]; result[k++] = this.ranges[i++]; } } this.ranges = result; }
synchronized RangeToken getCaseInsensitiveToken() { if (this.icaseCache != null) return this.icaseCache; RangeToken uppers = this.type == Token.RANGE ? Token.createRange() : Token.createNRange(); for (int i = 0; i < this.ranges.length; i += 2) { for (int ch = this.ranges[i]; ch <= this.ranges[i + 1]; ch++) { if (ch > 0xffff) uppers.addRange(ch, ch); else { char uch = Character.toUpperCase((char) ch); uppers.addRange(uch, uch); } } } RangeToken lowers = this.type == Token.RANGE ? Token.createRange() : Token.createNRange(); for (int i = 0; i < uppers.ranges.length; i += 2) { for (int ch = uppers.ranges[i]; ch <= uppers.ranges[i + 1]; ch++) { if (ch > 0xffff) lowers.addRange(ch, ch); else { char uch = Character.toUpperCase((char) ch); lowers.addRange(uch, uch); } } } lowers.mergeRanges(uppers); lowers.mergeRanges(this); lowers.compactRanges(); this.icaseCache = lowers; return lowers; }
/** for RANGE: Creates complement. for NRANGE: Creates the same meaning RANGE. */ static Token complementRanges(Token token) { if (token.type != RANGE && token.type != NRANGE) throw new IllegalArgumentException("Token#complementRanges(): must be RANGE: " + token.type); RangeToken tok = (RangeToken) token; tok.sortRanges(); tok.compactRanges(); int len = tok.ranges.length + 2; if (tok.ranges[0] == 0) len -= 2; int last = tok.ranges[tok.ranges.length - 1]; if (last == UTF16_MAX) len -= 2; RangeToken ret = Token.createRange(); ret.ranges = new int[len]; int wp = 0; if (tok.ranges[0] > 0) { ret.ranges[wp++] = 0; ret.ranges[wp++] = tok.ranges[0] - 1; } for (int i = 1; i < tok.ranges.length - 2; i += 2) { ret.ranges[wp++] = tok.ranges[i] + 1; ret.ranges[wp++] = tok.ranges[i + 1] - 1; } if (last != UTF16_MAX) { ret.ranges[wp++] = last + 1; ret.ranges[wp] = UTF16_MAX; } ret.setCompacted(); return ret; }
/** @param tok Ignore whether it is NRANGE or not. */ protected void intersectRanges(Token token) { RangeToken tok = (RangeToken) token; if (tok.ranges == null || this.ranges == null) return; this.icaseCache = null; this.sortRanges(); this.compactRanges(); tok.sortRanges(); tok.compactRanges(); int[] result = new int[this.ranges.length + tok.ranges.length]; int wp = 0, src1 = 0, src2 = 0; while (src1 < this.ranges.length && src2 < tok.ranges.length) { int src1begin = this.ranges[src1]; int src1end = this.ranges[src1 + 1]; int src2begin = tok.ranges[src2]; int src2end = tok.ranges[src2 + 1]; if (src1end < src2begin) { // Not overlapped // src1: o-----o // src2: o-----o // res: empty // Reuse src2 src1 += 2; } else if (src1end >= src2begin && src1begin <= src2end) { // Overlapped // src1: o--------o // src2: o----o // src2: o----o // src2: o----o // src2: o------------o if (src2begin <= src2begin && src1end <= src2end) { // src1: o--------o // src2: o------------o // res: o--------o // Reuse src2 result[wp++] = src1begin; result[wp++] = src1end; src1 += 2; } else if (src2begin <= src1begin) { // src1: o--------o // src2: o----o // res: o--o // Reuse the rest of src1 result[wp++] = src1begin; result[wp++] = src2end; this.ranges[src1] = src2end + 1; src2 += 2; } else if (src1end <= src2end) { // src1: o--------o // src2: o----o // res: o--o // Reuse src2 result[wp++] = src2begin; result[wp++] = src1end; src1 += 2; } else { // src1: o--------o // src2: o----o // res: o----o // Reuse the rest of src1 result[wp++] = src2begin; result[wp++] = src2end; this.ranges[src1] = src2end + 1; } } else if (src2end < src1begin) { // Not overlapped // src1: o-----o // src2: o----o src2 += 2; } else { throw new RuntimeException( "Token#intersectRanges(): Internal Error: [" + this.ranges[src1] + "," + this.ranges[src1 + 1] + "] & [" + tok.ranges[src2] + "," + tok.ranges[src2 + 1] + "]"); } } while (src1 < this.ranges.length) { result[wp++] = this.ranges[src1++]; result[wp++] = this.ranges[src1++]; } this.ranges = new int[wp]; System.arraycopy(result, 0, this.ranges, 0, wp); // this.ranges is sorted and compacted. }
protected void subtractRanges(Token token) { if (token.type == NRANGE) { this.intersectRanges(token); return; } RangeToken tok = (RangeToken) token; if (tok.ranges == null || this.ranges == null) return; this.icaseCache = null; this.sortRanges(); this.compactRanges(); tok.sortRanges(); tok.compactRanges(); // System.err.println("Token#substractRanges(): Entry: "+this.ranges.length+", // "+tok.ranges.length); int[] result = new int[this.ranges.length + tok.ranges.length]; int wp = 0, src = 0, sub = 0; while (src < this.ranges.length && sub < tok.ranges.length) { int srcbegin = this.ranges[src]; int srcend = this.ranges[src + 1]; int subbegin = tok.ranges[sub]; int subend = tok.ranges[sub + 1]; if (srcend < subbegin) { // Not overlapped // src: o-----o // sub: o-----o // res: o-----o // Reuse sub result[wp++] = this.ranges[src++]; result[wp++] = this.ranges[src++]; } else if (srcend >= subbegin && srcbegin <= subend) { // Overlapped // src: o--------o // sub: o----o // sub: o----o // sub: o----o // sub: o------------o if (subbegin <= srcbegin && srcend <= subend) { // src: o--------o // sub: o------------o // res: empty // Reuse sub src += 2; } else if (subbegin <= srcbegin) { // src: o--------o // sub: o----o // res: o-----o // Reuse src(=res) this.ranges[src] = subend + 1; sub += 2; } else if (srcend <= subend) { // src: o--------o // sub: o----o // res: o-----o // Reuse sub result[wp++] = srcbegin; result[wp++] = subbegin - 1; src += 2; } else { // src: o--------o // sub: o----o // res: o-o o-o // Reuse src(=right res) result[wp++] = srcbegin; result[wp++] = subbegin - 1; this.ranges[src] = subend + 1; sub += 2; } } else if (subend < srcbegin) { // Not overlapped // src: o-----o // sub: o----o sub += 2; } else { throw new RuntimeException( "Token#subtractRanges(): Internal Error: [" + this.ranges[src] + "," + this.ranges[src + 1] + "] - [" + tok.ranges[sub] + "," + tok.ranges[sub + 1] + "]"); } } while (src < this.ranges.length) { result[wp++] = this.ranges[src++]; result[wp++] = this.ranges[src++]; } this.ranges = new int[wp]; System.arraycopy(result, 0, this.ranges, 0, wp); // this.ranges is sorted and compacted. }