diff --git a/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala b/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala index 8ebbc573..f345fae0 100644 --- a/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala +++ b/src/main/scala/scala/util/parsing/combinator/RegexParsers.scala @@ -73,7 +73,7 @@ trait RegexParsers extends Parsers { */ protected def handleWhiteSpace(source: java.lang.CharSequence, offset: Int): Int = if (skipWhitespace) - (whiteSpace findPrefixMatchOf (source.subSequence(offset, source.length))) match { + (whiteSpace findPrefixMatchOf (new SubSequence(source, offset))) match { case Some(matched) => offset + matched.end case None => offset } @@ -107,7 +107,7 @@ trait RegexParsers extends Parsers { val source = in.source val offset = in.offset val start = handleWhiteSpace(source, offset) - (r findPrefixMatchOf (source.subSequence(start, source.length))) match { + (r findPrefixMatchOf (new SubSequence(source, start))) match { case Some(matched) => Success(source.subSequence(start, start + matched.end).toString, in.drop(start + matched.end - offset)) diff --git a/src/main/scala/scala/util/parsing/combinator/SubSequence.scala b/src/main/scala/scala/util/parsing/combinator/SubSequence.scala new file mode 100644 index 00000000..79c8acac --- /dev/null +++ b/src/main/scala/scala/util/parsing/combinator/SubSequence.scala @@ -0,0 +1,32 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + +package scala +package util.parsing.combinator + +// A shallow wrapper over another CharSequence (usually a String) +// +// See SI-7710: in jdk7u6 String.subSequence stopped sharing the char array of the original +// string and began copying it. +// RegexParsers calls subSequence twice per input character: that's a lot of array copying! +private[combinator] class SubSequence(s: CharSequence, start: Int, val length: Int) extends CharSequence { + def this(s: CharSequence, start: Int) = this(s, start, s.length - start) + + def charAt(i: Int) = + if (i >= 0 && i < length) s.charAt(start + i) else throw new IndexOutOfBoundsException(s"index: $i, length: $length") + + def subSequence(_start: Int, _end: Int) = { + if (_start < 0 || _end < 0 || _end > length || _start > _end) + throw new IndexOutOfBoundsException(s"start: ${_start}, end: ${_end}, length: $length") + + new SubSequence(s, start + _start, _end - _start) + } + + override def toString = s.subSequence(start, start + length).toString +}