diff --git a/src/main/scala/com/codecommit/antixml/Group.scala b/src/main/scala/com/codecommit/antixml/Group.scala index df62ded..bb6352e 100644 --- a/src/main/scala/com/codecommit/antixml/Group.scala +++ b/src/main/scala/com/codecommit/antixml/Group.scala @@ -165,6 +165,7 @@ class Group[+A <: Node] private[antixml] (private[antixml] val nodes: VectorCase new Group(nodes) with Zipper[A] { val map = Vector() def parent = error("Attempted to move up at root of the tree") + override val hasValidContext = false } } @@ -239,6 +240,8 @@ object Group { case group: Group[Node] => group.toZipper case _ => error("No zipper context available") } + + override val hasValidContext = from.isInstanceOf[Group[Node]] } } } @@ -248,6 +251,7 @@ object Group { new Group(vec) with Zipper[A] { lazy val map = baseMap def parent = error("No zipper context available") + override val hasValidContext = false } } } diff --git a/src/main/scala/com/codecommit/antixml/Zipper.scala b/src/main/scala/com/codecommit/antixml/Zipper.scala index 2430d91..f344a70 100644 --- a/src/main/scala/com/codecommit/antixml/Zipper.scala +++ b/src/main/scala/com/codecommit/antixml/Zipper.scala @@ -38,6 +38,7 @@ trait Zipper[+A <: Node] extends Group[A] with ScalaCompat { self => protected def map: Vector[Option[ZContext]] protected def parent: Zipper[Node] + protected val hasValidContext = true // TODO this *may* be a poor choice of words... def stripZipper = new Group(toVectorCase) @@ -67,52 +68,56 @@ trait Zipper[+A <: Node] extends Group[A] with ScalaCompat { self => override def flatMap[B, That](f: A => CompatTraversable[B])(implicit cbf: CanBuildFrom[Group[A], B, That]): That = cbf match { case cbf: CanBuildFromWithZipper[Group[A], B, That] => { - val result = toVectorCase.toVector map f - - val intermedMap = map map { - case Some((from, to, rebuild, childMap)) => { - // get the mapping from *our* indexes to source indexes - val inverseMap = { - val maps = for ((source, targets) <- childMap) - yield (Map[Int, Int]() /: targets) { (acc, t) => acc + (t -> source) } - - (Map[Int, Int]() /: maps) { _ ++ _ } - } - - val (_, aggregate, childMap2) = result.slice(from, to).zipWithIndex.foldLeft((0, Vector[B](), Map[Int, Set[Int]]())) { - case ((start, acc, childMap2), (chunk, i)) => { - val size = chunk.size - val source = inverseMap(i) - - val contrib = Set(start until (start + size): _*) - val set2 = childMap2.getOrElse(source, contrib) ++ contrib + if (!hasValidContext) { + super.flatMap(f)(cbf) // don't try to preserve + } else { + val result = toVectorCase.toVector map f - (start + size, acc ++ chunk, childMap2.updated(source, set2)) + val intermedMap = map map { + case Some((from, to, rebuild, childMap)) => { + // get the mapping from *our* indexes to source indexes + val inverseMap = { + val maps = for ((source, targets) <- childMap) + yield (Map[Int, Int]() /: targets) { (acc, t) => acc + (t -> source) } + + (Map[Int, Int]() /: maps) { _ ++ _ } + } + + val (_, aggregate, childMap2) = result.slice(from, to).zipWithIndex.foldLeft((0, Vector[B](), Map[Int, Set[Int]]())) { + case ((start, acc, childMap2), (chunk, i)) => { + val size = chunk.size + val source = inverseMap(i) + + val contrib = Set(start until (start + size): _*) + val set2 = childMap2.getOrElse(source, contrib) ++ contrib + + (start + size, acc ++ chunk, childMap2.updated(source, set2)) + } } + + val length = aggregate.length + val delta = length - (to - from) + Some((from, to + delta, rebuild, childMap2, aggregate, delta)) } - - val length = aggregate.length - val delta = length - (to - from) - Some((from, to + delta, rebuild, childMap2, aggregate, delta)) + + case None => None } - - case None => None - } - - val (_, map2, chunks) = intermedMap.foldLeft((0, Vector[Option[ZContext]](), Vector[Vector[B]]())) { - case ((offset, map2, acc), Some((from, to, rebuild, childMap, aggregate, delta))) => { - val from2 = from + offset - val to2 = to + offset - val offset2 = offset + delta - (offset2, map2 :+ Some((from2, to2, rebuild, childMap)), acc :+ aggregate) + + val (_, map2, chunks) = intermedMap.foldLeft((0, Vector[Option[ZContext]](), Vector[Vector[B]]())) { + case ((offset, map2, acc), Some((from, to, rebuild, childMap, aggregate, delta))) => { + val from2 = from + offset + val to2 = to + offset + val offset2 = offset + delta + (offset2, map2 :+ Some((from2, to2, rebuild, childMap)), acc :+ aggregate) + } + + case ((offset, map2, acc), None) => (offset, map2 :+ None, acc) } - - case ((offset, map2, acc), None) => (offset, map2 :+ None, acc) + + val builder = cbf(parent.asInstanceOf[Group[A]], map2) + chunks foreach (builder ++=) + builder.result } - - val builder = cbf(parent.asInstanceOf[Group[A]], map2) - chunks foreach (builder ++=) - builder.result } case _ => super.flatMap(f)(cbf)