summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-09-09 10:50:37 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-09-09 10:50:37 +0200
commit0729b29dd7a6f8c454234d2154db06c74b8cb05a (patch)
tree28c1470b9b765cd1f45ce68acb4aed1170e3be45
parent068237ab750b92d3b1e81876afaca0246416e1ea (diff)
parent3d64deeb687452cb7e8e53b5a172e7bc7c50bf1b (diff)
downloadscala-0729b29dd7a6f8c454234d2154db06c74b8cb05a.tar.gz
scala-0729b29dd7a6f8c454234d2154db06c74b8cb05a.tar.bz2
scala-0729b29dd7a6f8c454234d2154db06c74b8cb05a.zip
Merge pull request #3801 from Ichoran/issue/8474
SI-8474 Inconsistent behavior of patch method
-rw-r--r--src/library/scala/collection/Iterator.scala40
-rw-r--r--src/library/scala/collection/SeqViewLike.scala23
2 files changed, 47 insertions, 16 deletions
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index f6f46e158f..660cc5a42a 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -1088,6 +1088,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
}
/** Returns this iterator with patched values.
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original iterator appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
*
* @param from The start index from which to patch
* @param patchElems The iterator of patch values
@@ -1096,18 +1099,33 @@ trait Iterator[+A] extends TraversableOnce[A] {
*/
def patch[B >: A](from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] = new AbstractIterator[B] {
private var origElems = self
- private var i = 0
- def hasNext: Boolean =
- if (i < from) origElems.hasNext
- else patchElems.hasNext || origElems.hasNext
+ private var i = (if (from > 0) from else 0) // Counts down, switch to patch on 0, -1 means use patch first
+ def hasNext: Boolean = {
+ if (i == 0) {
+ origElems = origElems drop replaced
+ i = -1
+ }
+ origElems.hasNext || patchElems.hasNext
+ }
def next(): B = {
- // We have to do this *first* just in case from = 0.
- if (i == from) origElems = origElems drop replaced
- val result: B =
- if (i < from || !patchElems.hasNext) origElems.next()
- else patchElems.next()
- i += 1
- result
+ if (i == 0) {
+ origElems = origElems drop replaced
+ i = -1
+ }
+ if (i < 0) {
+ if (patchElems.hasNext) patchElems.next()
+ else origElems.next()
+ }
+ else {
+ if (origElems.hasNext) {
+ i -= 1
+ origElems.next()
+ }
+ else {
+ i = -1
+ patchElems.next()
+ }
+ }
}
}
diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala
index 5e31ac4a53..e719f19c78 100644
--- a/src/library/scala/collection/SeqViewLike.scala
+++ b/src/library/scala/collection/SeqViewLike.scala
@@ -154,17 +154,27 @@ trait SeqViewLike[+A,
}
}
+ // Note--for this to work, must ensure 0 <= from and 0 <= replaced
+ // Must also take care to allow patching inside an infinite stream
+ // (patching in an infinite stream is not okay)
trait Patched[B >: A] extends Transformed[B] {
protected[this] val from: Int
protected[this] val patch: GenSeq[B]
protected[this] val replaced: Int
private lazy val plen = patch.length
override def iterator: Iterator[B] = self.iterator patch (from, patch.iterator, replaced)
- def length: Int = self.length + plen - replaced
- def apply(idx: Int): B =
- if (idx < from) self.apply(idx)
- else if (idx < from + plen) patch.apply(idx - from)
+ def length: Int = {
+ val len = self.length
+ val pre = math.min(from, len)
+ val post = math.max(0, len - pre - replaced)
+ pre + plen + post
+ }
+ def apply(idx: Int): B = {
+ val actualFrom = if (self.lengthCompare(from) < 0) self.length else from
+ if (idx < actualFrom) self.apply(idx)
+ else if (idx < actualFrom + plen) patch.apply(idx - actualFrom)
else self.apply(idx - plen + replaced)
+ }
final override protected[this] def viewIdentifier = "P"
}
@@ -210,7 +220,10 @@ trait SeqViewLike[+A,
override def reverse: This = newReversed.asInstanceOf[This]
override def patch[B >: A, That](from: Int, patch: GenSeq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That = {
- newPatched(from, patch, replaced).asInstanceOf[That]
+ // Be careful to not evaluate the entire sequence! Patch should work (slowly, perhaps) on infinite streams.
+ val nonNegFrom = math.max(0,from)
+ val nonNegRep = math.max(0,replaced)
+ newPatched(nonNegFrom, patch, nonNegRep).asInstanceOf[That]
// was: val b = bf(repr)
// if (b.isInstanceOf[NoBuilder[_]]) newPatched(from, patch, replaced).asInstanceOf[That]
// else super.patch[B, That](from, patch, replaced)(bf)