| /* |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of |
| * this software and associated documentation files (the "Software"), to deal in |
| * the Software without restriction, including without limitation the rights to |
| * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is furnished to do |
| * so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| package jdk.nashorn.internal.runtime.regexp.joni; |
| |
| import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; |
| import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; |
| |
| @SuppressWarnings("javadoc") |
| public final class CodeRangeBuffer implements Cloneable { |
| private static final int INIT_MULTI_BYTE_RANGE_SIZE = 5; |
| private static final int ALL_MULTI_BYTE_RANGE = 0x7fffffff; |
| |
| int[] p; |
| int used; |
| |
| |
| public CodeRangeBuffer() { |
| p = new int[INIT_MULTI_BYTE_RANGE_SIZE]; |
| writeCodePoint(0, 0); |
| } |
| |
| // CodeRange.isInCodeRange |
| public boolean isInCodeRange(final int code) { |
| int low = 0; |
| final int n = p[0]; |
| int high = n; |
| |
| while (low < high) { |
| final int x = (low + high) >> 1; |
| if (code > p[(x << 1) + 2]) { |
| low = x + 1; |
| } else { |
| high = x; |
| } |
| } |
| return low < n && code >= p[(low << 1) + 1]; |
| } |
| |
| private CodeRangeBuffer(final CodeRangeBuffer orig) { |
| p = new int[orig.p.length]; |
| System.arraycopy(orig.p, 0, p, 0, p.length); |
| used = orig.used; |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder buf = new StringBuilder(); |
| buf.append("CodeRange"); |
| buf.append("\n used: ").append(used); |
| buf.append("\n code point: ").append(p[0]); |
| buf.append("\n ranges: "); |
| |
| for (int i=0; i<p[0]; i++) { |
| buf.append("[").append(rangeNumToString(p[i * 2 + 1])).append("..").append(rangeNumToString(p[i * 2 + 2])).append("]"); |
| if (i > 0 && i % 6 == 0) { |
| buf.append("\n "); |
| } |
| } |
| |
| return buf.toString(); |
| } |
| |
| private static String rangeNumToString(final int num){ |
| return "0x" + Integer.toString(num, 16); |
| } |
| |
| public void expand(final int low) { |
| int length = p.length; |
| do { length <<= 1; } while (length < low); |
| final int[]tmp = new int[length]; |
| System.arraycopy(p, 0, tmp, 0, used); |
| p = tmp; |
| } |
| |
| public void ensureSize(final int size) { |
| int length = p.length; |
| while (length < size ) { length <<= 1; } |
| if (p.length != length) { |
| final int[]tmp = new int[length]; |
| System.arraycopy(p, 0, tmp, 0, used); |
| p = tmp; |
| } |
| } |
| |
| private void moveRight(final int from, final int to, final int n) { |
| if (to + n > p.length) { |
| expand(to + n); |
| } |
| System.arraycopy(p, from, p, to, n); |
| if (to + n > used) { |
| used = to + n; |
| } |
| } |
| |
| protected void moveLeft(final int from, final int to, final int n) { |
| System.arraycopy(p, from, p, to, n); |
| } |
| |
| private void moveLeftAndReduce(final int from, final int to) { |
| System.arraycopy(p, from, p, to, used - from); |
| used -= from - to; |
| } |
| |
| public void writeCodePoint(final int pos, final int b) { |
| final int u = pos + 1; |
| if (p.length < u) { |
| expand(u); |
| } |
| p[pos] = b; |
| if (used < u) { |
| used = u; |
| } |
| } |
| |
| @Override |
| public CodeRangeBuffer clone() { |
| return new CodeRangeBuffer(this); |
| } |
| |
| // ugly part: these methods should be made OO |
| // add_code_range_to_buf |
| public static CodeRangeBuffer addCodeRangeToBuff(final CodeRangeBuffer pbufp, final int fromp, final int top) { |
| int from = fromp, to = top; |
| CodeRangeBuffer pbuf = pbufp; |
| |
| if (from > to) { |
| final int n = from; |
| from = to; |
| to = n; |
| } |
| |
| if (pbuf == null) { |
| pbuf = new CodeRangeBuffer(); // move to CClassNode |
| } |
| |
| final int[]p = pbuf.p; |
| int n = p[0]; |
| |
| int low = 0; |
| int bound = n; |
| |
| while (low < bound) { |
| final int x = (low + bound) >>> 1; |
| if (from > p[x * 2 + 2]) { |
| low = x + 1; |
| } else { |
| bound = x; |
| } |
| } |
| |
| int high = low; |
| bound = n; |
| |
| while (high < bound) { |
| final int x = (high + bound) >>> 1; |
| if (to >= p[x * 2 + 1] - 1) { |
| high = x + 1; |
| } else { |
| bound = x; |
| } |
| } |
| |
| final int incN = low + 1 - high; |
| |
| if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) { |
| throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES); |
| } |
| |
| if (incN != 1) { |
| if (from > p[low * 2 + 1]) { |
| from = p[low * 2 + 1]; |
| } |
| if (to < p[(high - 1) * 2 + 2]) { |
| to = p[(high - 1) * 2 + 2]; |
| } |
| } |
| |
| if (incN != 0 && high < n) { |
| final int fromPos = 1 + high * 2; |
| final int toPos = 1 + (low + 1) * 2; |
| final int size = (n - high) * 2; |
| |
| if (incN > 0) { |
| pbuf.moveRight(fromPos, toPos, size); |
| } else { |
| pbuf.moveLeftAndReduce(fromPos, toPos); |
| } |
| } |
| |
| final int pos = 1 + low * 2; |
| // pbuf.ensureSize(pos + 2); |
| pbuf.writeCodePoint(pos, from); |
| pbuf.writeCodePoint(pos + 1, to); |
| n += incN; |
| pbuf.writeCodePoint(0, n); |
| |
| return pbuf; |
| } |
| |
| // add_code_range, be aware of it returning null! |
| public static CodeRangeBuffer addCodeRange(final CodeRangeBuffer pbuf, final ScanEnvironment env, final int from, final int to) { |
| if (from > to) { |
| if (env.syntax.allowEmptyRangeInCC()) { |
| return pbuf; |
| } |
| throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); |
| } |
| return addCodeRangeToBuff(pbuf, from, to); |
| } |
| |
| // SET_ALL_MULTI_BYTE_RANGE |
| protected static CodeRangeBuffer setAllMultiByteRange(final CodeRangeBuffer pbuf) { |
| return addCodeRangeToBuff(pbuf, EncodingHelper.mbcodeStartPosition(), ALL_MULTI_BYTE_RANGE); |
| } |
| |
| // ADD_ALL_MULTI_BYTE_RANGE |
| public static CodeRangeBuffer addAllMultiByteRange(final CodeRangeBuffer pbuf) { |
| return setAllMultiByteRange(pbuf); |
| } |
| |
| // not_code_range_buf |
| public static CodeRangeBuffer notCodeRangeBuff(final CodeRangeBuffer bbuf) { |
| CodeRangeBuffer pbuf = null; |
| |
| if (bbuf == null) { |
| return setAllMultiByteRange(pbuf); |
| } |
| |
| final int[]p = bbuf.p; |
| final int n = p[0]; |
| |
| if (n <= 0) { |
| return setAllMultiByteRange(pbuf); |
| } |
| |
| int pre = EncodingHelper.mbcodeStartPosition(); |
| |
| int from; |
| int to = 0; |
| for (int i=0; i<n; i++) { |
| from = p[i * 2 + 1]; |
| to = p[i * 2 + 2]; |
| if (pre <= from - 1) { |
| pbuf = addCodeRangeToBuff(pbuf, pre, from - 1); |
| } |
| if (to == ALL_MULTI_BYTE_RANGE) { |
| break; |
| } |
| pre = to + 1; |
| } |
| |
| if (to < ALL_MULTI_BYTE_RANGE) { |
| pbuf = addCodeRangeToBuff(pbuf, to + 1, ALL_MULTI_BYTE_RANGE); |
| } |
| return pbuf; |
| } |
| |
| // or_code_range_buf |
| public static CodeRangeBuffer orCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p, |
| final CodeRangeBuffer bbuf2p, final boolean not2p) { |
| CodeRangeBuffer pbuf = null; |
| CodeRangeBuffer bbuf1 = bbuf1p; |
| CodeRangeBuffer bbuf2 = bbuf2p; |
| boolean not1 = not1p; |
| boolean not2 = not2p; |
| |
| if (bbuf1 == null && bbuf2 == null) { |
| if (not1 || not2) { |
| return setAllMultiByteRange(pbuf); |
| } |
| return null; |
| } |
| |
| if (bbuf2 == null) { |
| CodeRangeBuffer tbuf; |
| boolean tnot; |
| // swap |
| tnot = not1; not1 = not2; not2 = tnot; |
| tbuf = bbuf1; bbuf1 = bbuf2; bbuf2 = tbuf; |
| } |
| |
| if (bbuf1 == null) { |
| if (not1) { |
| return setAllMultiByteRange(pbuf); |
| } |
| if (!not2) { |
| return bbuf2.clone(); |
| } |
| return notCodeRangeBuff(bbuf2); |
| } |
| |
| if (not1) { |
| CodeRangeBuffer tbuf; |
| boolean tnot; |
| // swap |
| tnot = not1; not1 = not2; not2 = tnot; |
| tbuf = bbuf1; bbuf1 = bbuf2; bbuf2 = tbuf; |
| } |
| |
| if (!not2 && !not1) { /* 1 OR 2 */ |
| pbuf = bbuf2.clone(); |
| } else if (!not1) { /* 1 OR (not 2) */ |
| pbuf = notCodeRangeBuff(bbuf2); |
| } |
| |
| final int[]p1 = bbuf1.p; |
| final int n1 = p1[0]; |
| |
| for (int i=0; i<n1; i++) { |
| final int from = p1[i * 2 + 1]; |
| final int to = p1[i * 2 + 2]; |
| pbuf = addCodeRangeToBuff(pbuf, from, to); |
| } |
| |
| return pbuf; |
| } |
| |
| // and_code_range1 |
| public static CodeRangeBuffer andCodeRange1(final CodeRangeBuffer pbufp, final int from1p, final int to1p, final int[]data, final int n) { |
| CodeRangeBuffer pbuf = pbufp; |
| int from1 = from1p, to1 = to1p; |
| |
| for (int i=0; i<n; i++) { |
| final int from2 = data[i * 2 + 1]; |
| final int to2 = data[i * 2 + 2]; |
| if (from2 < from1) { |
| if (to2 < from1) { |
| continue; |
| } |
| from1 = to2 + 1; |
| } else if (from2 <= to1) { |
| if (to2 < to1) { |
| if (from1 <= from2 - 1) { |
| pbuf = addCodeRangeToBuff(pbuf, from1, from2 - 1); |
| } |
| from1 = to2 + 1; |
| } else { |
| to1 = from2 - 1; |
| } |
| } else { |
| from1 = from2; |
| } |
| if (from1 > to1) { |
| break; |
| } |
| } |
| |
| if (from1 <= to1) { |
| pbuf = addCodeRangeToBuff(pbuf, from1, to1); |
| } |
| |
| return pbuf; |
| } |
| |
| // and_code_range_buf |
| public static CodeRangeBuffer andCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p, |
| final CodeRangeBuffer bbuf2p, final boolean not2p) { |
| CodeRangeBuffer pbuf = null; |
| CodeRangeBuffer bbuf1 = bbuf1p; |
| CodeRangeBuffer bbuf2 = bbuf2p; |
| boolean not1 = not1p, not2 = not2p; |
| |
| if (bbuf1 == null) { |
| if (not1 && bbuf2 != null) { |
| return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */ |
| } |
| return null; |
| } else if (bbuf2 == null) { |
| if (not2) { |
| return bbuf1.clone(); |
| } |
| return null; |
| } |
| |
| if (not1) { |
| CodeRangeBuffer tbuf; |
| boolean tnot; |
| // swap |
| tnot = not1; not1 = not2; not2 = tnot; |
| tbuf = bbuf1; bbuf1 = bbuf2; bbuf2 = tbuf; |
| } |
| |
| final int[]p1 = bbuf1.p; |
| final int n1 = p1[0]; |
| final int[]p2 = bbuf2.p; |
| final int n2 = p2[0]; |
| |
| if (!not2 && !not1) { /* 1 AND 2 */ |
| for (int i=0; i<n1; i++) { |
| final int from1 = p1[i * 2 + 1]; |
| final int to1 = p1[i * 2 + 2]; |
| |
| for (int j=0; j<n2; j++) { |
| final int from2 = p2[j * 2 + 1]; |
| final int to2 = p2[j * 2 + 2]; |
| |
| if (from2 > to1) { |
| break; |
| } |
| if (to2 < from1) { |
| continue; |
| } |
| final int from = from1 > from2 ? from1 : from2; |
| final int to = to1 < to2 ? to1 : to2; |
| pbuf = addCodeRangeToBuff(pbuf, from, to); |
| } |
| } |
| } else if (!not1) { /* 1 AND (not 2) */ |
| for (int i=0; i<n1; i++) { |
| final int from1 = p1[i * 2 + 1]; |
| final int to1 = p1[i * 2 + 2]; |
| pbuf = andCodeRange1(pbuf, from1, to1, p2, n2); |
| } |
| } |
| |
| return pbuf; |
| } |
| } |